BSD 4_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sun, 25 Sep 1983 11:03:10 +0000 (03:03 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sun, 25 Sep 1983 11:03:10 +0000 (03:03 -0800)
Work on file usr/src/include/fcntl.h
Work on file usr/src/ucb/lisp/Makefile
Work on file usr/src/ucb/lisp/lispconf
Work on file usr/src/ucb/lisp/lispnews
Work on file usr/lisp/ch0.n
Work on file usr/lisp/ch1.n
Work on file usr/lisp/ch11.n
Work on file usr/lisp/ch2.n
Work on file usr/lisp/ch4.n
Work on file usr/lisp/ch6.n
Work on file usr/lisp/ch8.n
Work on file usr/src/ucb/lisp/franz/data.c
Work on file usr/src/ucb/lisp/franz/alloc.c
Work on file usr/src/ucb/lisp/franz/divbig.c
Work on file usr/src/ucb/lisp/franz/error.c
Work on file usr/src/ucb/lisp/franz/eval.c
Work on file usr/src/ucb/lisp/franz/eval2.c
Work on file usr/src/ucb/lisp/franz/fasl.c
Work on file usr/src/ucb/lisp/franz/fex1.c
Work on file usr/src/ucb/lisp/franz/fex2.c
Work on file usr/src/ucb/lisp/franz/fex3.c
Work on file usr/src/ucb/lisp/franz/frame.c
Work on file usr/src/ucb/lisp/franz/ffasl.c
Work on file usr/src/ucb/lisp/franz/inits.c
Work on file usr/src/ucb/lisp/franz/io.c
Work on file usr/src/ucb/lisp/franz/lam1.c
Work on file usr/src/ucb/lisp/franz/lam3.c
Work on file usr/src/ucb/lisp/franz/lam2.c
Work on file usr/src/ucb/lisp/franz/lam5.c
Work on file usr/src/ucb/lisp/franz/lam7.c
Work on file usr/src/ucb/lisp/franz/lam6.c
Work on file usr/src/ucb/lisp/franz/lam8.c
Work on file usr/src/ucb/lisp/franz/lisp.c
Work on file usr/src/ucb/lisp/franz/pbignum.c
Work on file usr/src/ucb/lisp/franz/rlc.c
Work on file usr/src/ucb/lisp/franz/subbig.c
Work on file usr/src/ucb/lisp/franz/sysat.c
Work on file usr/src/ucb/lisp/franz/trace.c
Work on file usr/src/ucb/lisp/franz/68k/Makefile
Work on file usr/src/ucb/lisp/franz/h/config.h
Work on file usr/src/ucb/lisp/franz/68k/qfuncl.c
Work on file usr/src/ucb/lisp/franz/h/frame.h
Work on file usr/src/ucb/lisp/franz/h/global.h
Work on file usr/src/ucb/lisp/franz/vax/Makefile
Work on file usr/src/ucb/lisp/franz/vax/qfuncl.c
Work on file usr/src/ucb/lisp/lisplib/Makefile
Work on file usr/src/ucb/lisp/franz/vax/vax.c
Work on file usr/src/ucb/lisp/lisplib/buildlisp.l
Work on file usr/src/ucb/lisp/lisplib/common0.l
Work on file usr/src/ucb/lisp/lisplib/common1.l
Work on file usr/src/ucb/lisp/lisplib/common2.l
Work on file usr/src/ucb/lisp/lisplib/fix.l
Work on file usr/src/ucb/lisp/lisplib/lmhacks.l
Work on file usr/src/ucb/lisp/lisplib/macros.l
Work on file usr/src/ucb/lisp/lisplib/pp.l
Work on file usr/src/ucb/lisp/lisplib/struct.l
Work on file usr/src/ucb/lisp/lisplib/toplevel.l
Work on file usr/src/ucb/lisp/lisplib/tpl.l
Work on file usr/src/ucb/lisp/lisplib/trace.l
Work on file usr/src/ucb/lisp/lisplib/version.l
Work on file usr/src/ucb/lisp/lisplib/vector.l
Work on file usr/src/ucb/lisp/lisplib/manual/ch0.r
Work on file usr/src/ucb/lisp/lisplib/manual/ch11.r
Work on file usr/src/ucb/lisp/lisplib/manual/ch1.r
Work on file usr/src/ucb/lisp/lisplib/manual/ch12.r
Work on file usr/src/ucb/lisp/lisplib/manual/ch2.r
Work on file usr/src/ucb/lisp/lisplib/manual/ch4.r
Work on file usr/src/ucb/lisp/lisplib/manual/ch6.r
Work on file usr/src/ucb/lisp/lisplib/manual/ch8.r
Work on file usr/src/ucb/lisp/liszt/Makefile
Work on file usr/src/ucb/lisp/liszt/ChangeLog
Work on file usr/src/ucb/lisp/liszt/array.l
Work on file usr/src/ucb/lisp/liszt/chead.l
Work on file usr/src/ucb/lisp/liszt/cmacros.l
Work on file usr/src/ucb/lisp/liszt/cmake.l
Work on file usr/src/ucb/lisp/liszt/datab.l
Work on file usr/src/ucb/lisp/liszt/decl.l
Work on file usr/src/ucb/lisp/liszt/fixnum.l
Work on file usr/src/ucb/lisp/liszt/expr.l
Work on file usr/src/ucb/lisp/liszt/funa.l
Work on file usr/src/ucb/lisp/liszt/funb.l
Work on file usr/src/ucb/lisp/liszt/func.l
Work on file usr/src/ucb/lisp/liszt/lversion.l
Work on file usr/src/ucb/lisp/liszt/lxref.l
Work on file usr/src/ucb/lisp/liszt/tlev.l
Work on file usr/src/ucb/lisp/liszt/util.l
Work on file usr/src/ucb/lisp/liszt/68k/Makefile
Work on file usr/src/ucb/lisp/liszt/68k/Makefile2
Work on file usr/src/ucb/lisp/liszt/vax/Makefile
Work on file usr/src/ucb/lisp/pearl/Makefile
Work on file usr/src/ucb/lisp/pearl/ChangeLog
Work on file usr/src/ucb/lisp/pearl/ReadMe
Work on file usr/src/ucb/lisp/pearl/create.l
Work on file usr/src/ucb/lisp/pearl/hash.l
Work on file usr/src/ucb/lisp/pearl/hook.l
Work on file usr/src/ucb/lisp/pearl/print.l
Work on file usr/src/ucb/lisp/utils/tackon.c
Work on file usr/src/ucb/lisp/franz/68k/fixregs.sed
Work on file usr/src/ucb/lisp/lisplib/common3.l

Synthesized-from: CSRG/cd1/4.2

99 files changed:
usr/lisp/ch0.n [new file with mode: 0644]
usr/lisp/ch1.n [new file with mode: 0644]
usr/lisp/ch11.n [new file with mode: 0644]
usr/lisp/ch2.n [new file with mode: 0644]
usr/lisp/ch4.n [new file with mode: 0644]
usr/lisp/ch6.n [new file with mode: 0644]
usr/lisp/ch8.n [new file with mode: 0644]
usr/src/include/fcntl.h [new file with mode: 0644]
usr/src/ucb/lisp/Makefile [new file with mode: 0644]
usr/src/ucb/lisp/franz/68k/Makefile [new file with mode: 0644]
usr/src/ucb/lisp/franz/68k/fixregs.sed [new file with mode: 0644]
usr/src/ucb/lisp/franz/68k/qfuncl.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/alloc.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/data.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/divbig.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/error.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/eval.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/eval2.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/fasl.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/fex1.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/fex2.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/fex3.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/ffasl.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/frame.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/h/config.h [new file with mode: 0644]
usr/src/ucb/lisp/franz/h/frame.h [new file with mode: 0644]
usr/src/ucb/lisp/franz/h/global.h [new file with mode: 0644]
usr/src/ucb/lisp/franz/inits.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/io.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/lam1.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/lam2.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/lam3.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/lam5.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/lam6.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/lam7.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/lam8.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/lisp.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/pbignum.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/rlc.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/subbig.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/sysat.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/trace.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/vax/Makefile [new file with mode: 0644]
usr/src/ucb/lisp/franz/vax/qfuncl.c [new file with mode: 0644]
usr/src/ucb/lisp/franz/vax/vax.c [new file with mode: 0644]
usr/src/ucb/lisp/lispconf [new file with mode: 0755]
usr/src/ucb/lisp/lisplib/Makefile [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/buildlisp.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/common0.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/common1.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/common2.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/common3.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/fix.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/lmhacks.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/macros.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/manual/ch0.r [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/manual/ch1.r [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/manual/ch11.r [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/manual/ch12.r [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/manual/ch2.r [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/manual/ch4.r [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/manual/ch6.r [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/manual/ch8.r [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/pp.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/struct.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/toplevel.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/tpl.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/trace.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/vector.l [new file with mode: 0644]
usr/src/ucb/lisp/lisplib/version.l [new file with mode: 0644]
usr/src/ucb/lisp/lispnews [new file with mode: 0644]
usr/src/ucb/lisp/liszt/68k/Makefile [new file with mode: 0644]
usr/src/ucb/lisp/liszt/68k/Makefile2 [new file with mode: 0644]
usr/src/ucb/lisp/liszt/ChangeLog [new file with mode: 0644]
usr/src/ucb/lisp/liszt/Makefile [new file with mode: 0644]
usr/src/ucb/lisp/liszt/array.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/chead.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/cmacros.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/cmake.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/datab.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/decl.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/expr.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/fixnum.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/funa.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/funb.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/func.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/lversion.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/lxref.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/tlev.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/util.l [new file with mode: 0644]
usr/src/ucb/lisp/liszt/vax/Makefile [new file with mode: 0644]
usr/src/ucb/lisp/pearl/ChangeLog [new file with mode: 0644]
usr/src/ucb/lisp/pearl/Makefile [new file with mode: 0644]
usr/src/ucb/lisp/pearl/ReadMe [new file with mode: 0644]
usr/src/ucb/lisp/pearl/create.l [new file with mode: 0644]
usr/src/ucb/lisp/pearl/hash.l [new file with mode: 0644]
usr/src/ucb/lisp/pearl/hook.l [new file with mode: 0644]
usr/src/ucb/lisp/pearl/print.l [new file with mode: 0644]
usr/src/ucb/lisp/utils/tackon.c [new file with mode: 0644]

diff --git a/usr/lisp/ch0.n b/usr/lisp/ch0.n
new file mode 100644 (file)
index 0000000..4d18769
--- /dev/null
@@ -0,0 +1,180 @@
+." $Header: ch0.n 1.3 83/07/27 15:10:52 layer Exp $
+.pp
+\ \ 
+.sp 2i
+.tl ''\s14The\ \s16F\s14RANZ\ \s16L\s14ISP\ \s14Manual''
+.ps 10
+.sp 1v
+.tl ''by''
+.sp 2v
+.tl ''\fIJohn\ K.\ Foderaro\fP''
+.sp 2v
+.tl ''\fIKeith\ L.\ Sklower\fP''
+.sp 2v
+.tl ''\fIKevin\ Layer\fP''
+.sp 2i
+.tl ''June 1983''
+.sp 2i
+.tl '''A document in'
+.tl '''four movements'
+.bp
+.sp 1i
+.ft I
+.ll 5.5i
+.in .5i
+.tl ''Overture''
+.sp 2v
+A chorus of students
+under the direction of
+Richard Fateman have contributed to
+building 
+.Fr
+from a mere melody into a full
+symphony .
+The major contributors to the initial system were
+Mike Curry,  John Breedlove and Jeff Levinsky.
+Bill Rowan added the garbage collector and array package.
+Tom London worked on an early compiler and helped in 
+overall system design.
+Keith Sklower has contributed much to 
+.Fr ,
+adding the 
+bignum package and rewriting most of the code to increase
+its efficiency and clarity.
+Kipp Hickman and Charles Koester added hunks.
+Mitch Marcus added *rset, evalhook and evalframe.
+Don Cohen and others at Carnegie-Mellon 
+made some improvements to evalframe and 
+provided various features modelled after UCI/CMU PDP-10 Lisp and
+Interlisp environments (editor, debugger, top-level).
+John Foderaro wrote the compiler, added a few functions,
+and wrote much of this manual. Of course, other authors have
+contributed specific chapters as indicated.
+Kevin Layer modified the compiler to produce code for the
+Motorola 68000, and help make
+.Fr
+pass ``Lint''.
+.br
+This manual may be supplemented or supplanted by local
+chapters representing alterations, additions and deletions.
+We at U.C. Berkeley are pleased to learn of generally
+useful system features, bug fixes, or useful program packages,
+and we will attempt to redistribute such contributions.
+.sp 1.75i
+.ft R
+.ll 6.0i
+.in 0
+\(co 1980, 1981, 1983 by the Regents of the University of California.
+(exceptions: Chapters 13, 14 (first half), 15 and 16 have separate copyrights,
+as indicated. These are reproduced by permission of the copyright
+holders.)
+.br
+Permission to copy without fee all or part of this material is granted
+provided that the copies are not made or
+distributed for direct commercial advantage, and the copyright
+notice of the Regents, University of California, is given.
+All rights reserved.
+.br
+.sp 2v
+Work reported herein was supported in part by 
+the U. S. Department
+of Energy, Contract DE-AT03-76SF00034, Project Agreement
+DE-AS03-79ER10358, and the National Science
+Foundation under Grant No.  MCS 7807291
+.sp 2v
+UNIX is a trademark of Bell Laboratories.  VAX and PDP are trademarks
+of Digital Equiptment Coporation.  MC68000 is a trademark of
+Motorola Semiconductor Products, Inc.
+.bp
+.ps 16
+.sp 1i
+.tl ''Score''
+.sp .5i
+.ps 12
+.in 1i.
+.ti 2i
+\fBFirst Movement \fI(allegro non troppo)\fR
+.ps 10
+.sp 1v
+.de CH
+.ti -.5i
+\fR\\$1 \\$2\fP
+.br
+..
+.ft I
+.CH 1. F\s-2RANZ\s0\ L\s-2ISP\s0 
+Introduction to 
+.Fr ,
+details of data types,
+and description of notation
+.CH 2. Data\ Structure\ Access
+Functions for the creation, destruction  
+and  manipulation of lisp data objects.
+.CH 3. Arithmetic\ Functions
+Functions to perform arithmetic operations.
+.CH 4. Special\ Functions
+Functions for altering flow of control.
+Functions for mapping other functions over lists.
+.CH 5. I/O\ Functions
+Functions for reading and writing from ports.
+Functions for the modification of the reader's syntax.
+.CH 6. System\ Functions 
+Functions for storage management, debugging, and for the reading 
+and setting of global Lisp status variables.
+Functions for doing UNIX-specific tasks such as process control.
+.ft R
+.sp 2v
+.ps 12
+.ti 2i
+\fBSecond Movement \fI(Largo)\fR
+.ps 10
+.sp 1v
+.ft I
+.CH 7. The\ Reader
+A description of the syntax codes used by the reader.
+An explanation of character macros.
+.CH 8. Functions,\ Fclosures,\ and\ Macros 
+A description of various types of functional objects.
+An example of the use of foreign functions.
+.CH 9. Arrays\ and\ Vectors
+A detailed description of the parts of an array and of 
+Maclisp compatible arrays.
+.CH 10. Exception\ Handling 
+A description of the error handling sequence and of autoloading.
+.ft R
+.bp
+.ps 12
+.ti 2i
+\fBThird Movement \fI(Scherzo)\fR
+.ps 10
+.sp 1v
+.ft I
+.CH 11. The\ Joseph\ Lister\ Trace\ Package 
+A description of a very useful debugging aid.
+.CH 12. Liszt,\ the\ lisp\ compiler 
+A description of the operation of the
+compiler and hints for making functions compilable.
+.CH 13. CMU\ Top\ Level\ and\ file\ package
+A description of a top level with a history mechanism and a 
+package which helps you keep track of files of lisp functions.
+.CH 14 Stepper
+A description of a program which permits you to  put breakpoints
+in lisp code and to single step it.  A description of the
+evalhook and funcallhook mechanism.
+.CH 15 Fixit
+A program which permits you to examine and modify evaluation stack 
+in order to fix bugs on the fly.
+.CH 16 Lisp\ Editor
+A structure editor for interactive modification of lisp code.
+.ft R
+.sp 2v
+.ps 12
+.ti 2i
+\fBFinal Movement \fI(allegro)\fR
+.ps 10
+.sp 1v
+.ft I
+.CH Appendix\ A -\ Function\ Index 
+.CH Appendix\ B -\ List\ of\ Special\ Symbols
+.CH Appendix\ C -\ Short\ Subjects
+Garbage collector, Debugging, Default Top Level
diff --git a/usr/lisp/ch1.n b/usr/lisp/ch1.n
new file mode 100644 (file)
index 0000000..52c8c71
--- /dev/null
@@ -0,0 +1,486 @@
+." $Header: ch1.n 1.3 83/07/27 15:11:17 layer Exp $
+.Lc \s+2F\s-2RANZ\s0\ L\s-2ISP\s0\s-2 1
+.sh 2
+.Fr \*[\(dg\*]
+was created as a tool to further research in symbolic and
+algebraic manipulation,
+artificial intelligence,
+and programming languages at the University of California
+at Berkeley.
+.(f
+\*[\(dg\*]It is rumored that this name has something to do with Franz
+Liszt [F\fIr\fPa\*:nts List] (1811-1886) a Hungarian composer
+and keyboard virtuoso. 
+These allegations have never been proven.
+.)f
+Its roots are in a PDP-11 Lisp system which originally came
+from Harvard.
+As it grew it adopted features of Maclisp and Lisp Machine Lisp
+which enables our work to be shared with colleagues at
+the Laboratory for Computer Science at M.I.T.
+Substantial compatibility with other Lisp dialects
+(Interlisp, UCILisp, CMULisp) is achieved by 
+means of support packages and compiler switches.
+The heart of
+.Fr
+is written almost entirely in the programming language C.
+Of course, it has been greatly extended by additions written
+in Lisp.
+A small part is written in the assembly language for the current
+host machines, VAXen and a couple of flavors of 68000.
+Because 
+.Fr
+is written in C, it is relatively portable and easy to comprehend.
+.pp
+.Fr
+is capable of running large lisp programs in a timesharing environment,
+has facilities for arrays and user defined structures,
+has a user controlled reader with character and word macro  capabilities,
+and can interact directly with compiled Lisp, C, Fortran, and Pascal code.
+.pp 
+This document is a reference manual for the 
+.Fr
+system.
+It is not a Lisp primer or introduction to the language.
+Some parts will be of interest only to those maintaining 
+.Fr
+at their computer site.
+This document is divided into four Movements.
+In the first one we will attempt to describe the language of
+.Fr
+precisely and completely as it now stands (Opus 38.69, June 1983).
+In the second Movement we will look at the reader, function types,
+arrays and exception handling.
+In the third Movement we will look at several large support packages 
+written to help the 
+.Fr
+user, namely the trace package,  compiler, fixit and stepping package.
+Finally the fourth movement contains  an index into the other movements.
+In the rest of this chapter we shall examine the data types of 
+.Fr .
+The conventions used in the description of the 
+.Fr
+functions will be given in \(sc1.3 -- it is very important that 
+these conventions are  understood.
+.sh 2 Data\ Types
+.Fr
+has fourteen data types.
+In this section we shall look in detail at each type and if a type is
+divisible we shall look inside it.
+There is a Lisp function
+.i type
+which will return the type name of a lisp object.
+This is the official 
+.Fr
+name for that type and we will use this name and this name only in 
+the manual to avoid confusing the reader.
+The types are listed in terms of importance rather than alphabetically.
+.sh 3 lispval - - 0
+This is the name we use to describe any lisp object.
+The function
+.i type
+will never return `lispval'.
+.sh 3 symbol
+This object corresponds to a variable in most other programming languages.
+It may have a value or may be `unbound'.
+A symbol may be 
+.i lambda 
+.i bound 
+meaning that its current value is stored
+away somewhere and the symbol  is given a new value for the duration of a 
+certain context.
+When the Lisp processor  leaves that context, the 
+symbol's current value is thrown
+away and its old value is restored.
+.sp .5v
+A symbol may also have a 
+.i function 
+.i binding .
+This function binding is static; it cannot be lambda bound.
+Whenever the symbol is used in the functional position of a Lisp expression
+the function binding of the symbol is examined (see Chapter 4 for more
+details on  evaluation).
+.sp .5v
+A symbol may also have a 
+.i property 
+.i list ,
+another static data structure.
+The property list consists of a list of an even number of elements,
+considered to be grouped as pairs. 
+The first element of the pair is the 
+.i indicator 
+the second the 
+.i value 
+of that indicator.
+.sp .5v
+Each symbol has a print name 
+.i (pname) 
+which is how this symbol is accessed from input and referred to
+on  (printed) output.
+.sp .5v
+A symbol also has a hashlink used to link symbols together in the
+oblist -- this field is inaccessible to the lisp user.
+.sp .5v
+Symbols are created by the reader and by the functions
+.i concat ,
+.i maknam
+and their derivatives.
+Most symbols live on 
+.Fr 's
+sole 
+.i oblist ,
+and therefore two symbols with the same print name are
+usually the  exact same object (they are
+.i eq ).
+Symbols which are not on the oblist are said to be 
+.i uninterned.
+The function
+.i maknam
+creates uninterned symbols while 
+.i concat
+creates 
+.i interned 
+ones.
+.sp 1v
+.TS
+box center ; 
+c | c | c |  c .
+Subpart name   Get value       Set value       Type
+
+=
+value  eval    set     lispval
+               setq
+_
+property       plist   setplist        list or nil
+list   get     putprop 
+               defprop 
+_
+function       getd    putd    array, binary, list
+binding                def     or nil
+_
+print name     get_pname               string
+_
+hash link
+.TE
+.sh 3 list
+A list cell has two parts, called the car and cdr.
+List cells are created by the function 
+.i cons .
+.sp 1v
+.TS
+box center ;
+c | c | c | c .
+Subpart name   Get value       Set value       Type
+
+=
+car    car     rplaca  lispval
+_
+cdr    cdr     rplacd  lispval
+.TE
+.sh 3 binary
+This type acts as a function header for machine coded functions.
+It has two parts, a pointer to the start of the function and a
+symbol whose print name describes the 
+argument
+.i discipline .
+The discipline (if 
+.i lambda ,
+.i macro 
+or 
+.i nlambda )
+determines whether the arguments to this function will be evaluated
+by the caller
+before this function is called.
+If the discipline is a string (specifically 
+"\fIsubroutine\fP",
+"\fIfunction\fP",
+"\fIinteger-function\fP",
+"\fIreal-function\fP",
+"\fIc-function\fP",
+"\fIdouble-c-function\fP",
+or "\fIvector-c-function\fP"
+)
+then this function is
+a foreign subroutine or function (see \(sc8.5 for more details on this).
+Although the type of the 
+.i entry 
+field of a binary type object is usually \fBstring\fP or \fBother\fP,
+the object pointed to
+is actually a sequence of machine instructions.
+.br
+Objects of type binary are created by 
+.i mfunction,
+.i cfasl,
+and
+.i getaddress.
+.sp 1v
+.TS
+box center ;
+c | c | c | c .
+Subpart name   Get value       Set value       Type
+
+=
+entry  getentry                string or fixnum
+_
+discipline     getdisc putdisc symbol or fixnum
+.TE
+.sh 3 fixnum
+A fixnum is an integer constant in the range \(mi2\*[31\*] to
+2\*[31\*]\(mi1.
+Small fixnums (-1024 to 1023) are stored in a special table so they needn't be
+allocated each time one is needed.
+.sh 3 flonum
+A flonum is a double precision real number in the range 
+\(+-2.9\(mu10\*[-37\*] to \(+-1.7\(mu10\*[38\*].
+There are approximately sixteen decimal digits of precision.
+.sh 3 bignum
+A bignum is an integer of potentially unbounded size.
+When integer arithmetic exceeds the limits of fixnums mentioned above,
+the calculation is automatically done with bignums.
+Should calculation with bignums give a result which can be represented
+as a fixnum, then the fixnum representation will be used\*[\(dg\*].
+.(f
+\*[\(dg\*]The current algorithms for integer arithmetic operations will return
+(in certain cases) a result 
+between \(+-2\*[30\*] and 2\*[31\*] as a bignum although this
+could be represented as a fixnum.
+.)f
+This contraction is known as
+.i integer
+.i normalization .
+Many Lisp functions assume that integers are normalized.
+Bignums are composed of a sequence of
+.b list
+cells and a cell known as an 
+.b sdot.
+The user should consider a 
+.b bignum
+structure indivisible and use functions such as
+.i haipart ,
+and 
+.i bignum-leftshift
+to extract parts of it.
+.sh 3 string
+A string is a null terminated sequence of characters.
+Most functions of symbols which operate on the symbol's print name will
+also work on strings.
+The default reader syntax is set so that 
+a sequence of characters surrounded by double quotes is a string.
+.sh 3  port
+A port is a structure which the system I/O routines can reference to
+transfer data between the Lisp system and external media.
+Unlike other Lisp objects there are a very limited number of ports (20).
+Ports are allocated by 
+.i infile 
+and 
+.i outfile 
+and deallocated by 
+.i close 
+and 
+.i resetio .
+The 
+.i print
+function prints a port as a percent sign followed by the name of the file it
+is connected to (if the port was opened by \fIfileopen, infile, or outfile\fP).
+During initialization,
+.Fr
+binds the symbol \fBpiport\fP to a port attached to the standard input stream.
+This port prints as %$stdin.
+There are ports connected to the standard output and error streams,
+which print as %$stdout and %$stderr.
+This is discussed in more detail at the beginning of Chapter 5.
+.sh 3 vector
+Vectors are indexed sequences of data.
+They can be used to implement a notion of user-defined types,
+via their associated property list.
+They make \fBhunks\fP (see below) logically unnecessary, although hunks are very
+efficiently garbage collected.
+There is a second kind of vector, called an immediate-vector,
+which stores binary data.
+The name that the function \fItype\fP returns for immediate-vectors
+is \fBvectori\fP.
+Immediate-vectors could be used to implement strings and block-flonum arrays,
+for example.
+Vectors are discussed in chapter 9.
+The functions
+\fInew-vector\fP, and
+\fIvector\fP, can
+be used to create vectors.
+.sp 1v
+.TS
+box center ;
+c | c | c | c .
+Subpart name   Get value       Set value       Type
+
+=
+datum[\fIi\fP] vref    vset    lispval
+_
+property       vprop   vsetprop        lispval
+               vputprop
+_
+size   vsize   \-      fixnum
+.TE
+.sh 3 array
+Arrays are rather complicated types and are fully described in
+Chapter 9.
+An array consists of a block of contiguous data, a function
+to access that data and auxiliary fields for use by the accessing
+function.
+Since an array's accessing function is created by the user, an array can
+have any form the user chooses (e.g. n-dimensional, triangular, or hash
+table).
+.br
+Arrays are created by the function
+.i marray .
+.sp 1v
+.TS
+box center ;
+c | c | c | c .
+Subpart name   Get value       Set value       Type
+
+=
+access function        getaccess       putaccess       binary, list
+                       or symbol
+_
+auxiliary      getaux  putaux  lispval
+_
+data   arrayref        replace block of contiguous
+               set     lispval
+_
+length getlength       putlength       fixnum
+_
+delta  getdelta        putdelta        fixnum
+.TE
+.sh 3 value
+A value cell contains a pointer to a lispval.
+This type is used mainly by arrays of general lisp objects.
+Value cells are created with the 
+.i ptr
+function.
+A value cell containing a pointer to the symbol `foo' is printed
+as `(ptr\ to)foo'
+.sh 3 hunk
+A hunk is a vector of from 1 to 128 lispvals.
+Once a hunk is created (by 
+.i hunk 
+or 
+.i makhunk ) 
+it cannot grow or shrink.
+The access time for an element of a hunk is slower than a list cell element
+but faster than an array.
+Hunks are really only allocated in sizes which are powers of two, but 
+can appear to the user to be any size in the 1 to 128 range.
+Users of hunks must realize that \fI(not\ (atom\ 'lispval))\fP
+will return true if 
+.i lispval
+is a hunk.
+Most lisp systems do not have a direct test for a list cell and instead use
+the above test and assume that 
+a true result means 
+.i lispval 
+is a list cell.
+In
+.Fr
+you can use
+.i dtpr
+to check for a list cell.
+Although hunks are not list cells, you can still access the first two
+hunk elements with 
+.i cdr
+and
+.i car
+and you can access any hunk element with
+.i cxr \*[\(dg\*].
+.(f
+\*[\(dg\*]In a hunk, the function 
+.i cdr
+references the first element 
+and 
+.i car
+the second.
+.)f
+You can set the value of the first two elements of a hunk with 
+.i rplacd
+and 
+.i rplaca
+and you can set the value of any element of the hunk with 
+.i rplacx .
+A hunk is printed by printing its contents surrounded by { and }.
+However a hunk cannot be read in in this way in the standard lisp system.
+It is easy to write a reader macro to do this if desired.
+.sh 3 other
+Occasionally, you can obtain a pointer to storage not allocated
+by the lisp system.  One example of this is the entry field of
+those
+.Fr
+functions written in C.  Such objects are classified as of type
+\fBother\fP.
+Foreign functions which call malloc to allocate their own space,
+may also inadvertantly create such objects.
+The garbage collector is supposed to ignore such objects.
+.sh 2 Documentation Conventions.
+The conventions used in the following chapters were designed to
+give a great deal of information in a brief
+space.
+The first line of a function description contains the function
+name in \fBbold\ face\fP and then lists the arguments, if any.
+The arguments all have names which begin with a letter  or letters and 
+an underscore.
+The letter(s) gives the allowable type(s) for that argument according to
+this table.
+.sp 1v
+.TS
+box center ;
+c  | c 
+l | l .
+Letter Allowable type(s)
+
+=
+g      any type
+_
+s      symbol (although nil may not be allowed)
+_
+t      string
+_
+l      list (although nil may be allowed)
+_
+n      number (fixnum, flonum, bignum)
+_
+i      integer (fixnum, bignum)
+_
+x      fixnum
+_
+b      bignum
+_
+f      flonum
+_
+u      function type (either binary or lambda body)
+_
+y      binary
+_
+v      vector
+_
+V      vectori
+_
+a      array
+_
+e      value
+_
+p      port (or nil)
+_
+h      hunk
+.TE
+
+In the first line of a function description,
+those arguments preceded by a quote mark are evaluated (usually 
+before the function is called).
+The quoting convention is used so that we can give a name to the result of
+evaluating the argument and we can describe the allowable types.
+If an argument is not quoted it does not mean that that argument will
+not be evaluated, but rather that 
+if it is evaluated, the time at which it is evaluated
+will be specifically mentioned in the function description.
+Optional arguments are surrounded by square brackets.
+An ellipsis (...) means zero or more occurrences of an argument of the 
+directly preceding
+type.
diff --git a/usr/lisp/ch11.n b/usr/lisp/ch11.n
new file mode 100644 (file)
index 0000000..b0575f6
--- /dev/null
@@ -0,0 +1,237 @@
+." $Header: ch11.n 1.1 83/01/31 07:08:25 jkf Exp $
+.Lc The\ Joseph\ Lister\ Trace\ Package 11
+.de Tf
+.sp 2v
+.ti -.5i
+\fB\\$1\fP - 
+..
+.pp
+The Joseph Lister\*[\(dg\*] Trace package is an 
+important tool for the interactive debugging of a Lisp
+program.
+.(f
+\*[\(dg\*]\fILister, Joseph\fP\ \ \ \ 
+1st Baron Lister of Lyme Regis,
+1827-1912; English surgeon: introduced antiseptic surgery.
+.)f
+It allows you to examine selected  calls to a function or functions, and
+optionally to stop execution of the Lisp program to examine the values
+of variables.
+.pp
+The trace package is a set of Lisp programs located in the Lisp program 
+library (usually in the file /usr/lib/lisp/trace.l).
+Although not normally loaded in the Lisp system, the package will
+be loaded in when the first call to \fItrace\fP is made.
+.Lf trace "[ls_arg1 ...]"
+.Wh
+the form of the ls_arg\fIi\fP is described below.
+.Re
+a list of the function sucessfully modified for tracing.
+If no arguments are given to 
+.i trace ,
+a list of all functions currently being traced is returned.
+.Se
+The function definitions of the functions to trace are modified.
+.sp 2v
+.in 0
+The ls_arg\fIi\fP can have one of the following forms:
+.in .75i
+.Tf "foo"
+when foo is entered and exited, the trace information will be printed.
+.Tf "(foo break)"
+when foo is entered and exited the trace information will be printed.
+Also, just after the trace information for foo is printed upon entry,
+you will be put in  a special break loop.
+The prompt is `T>' and you may type any Lisp expression, and see its
+value printed.
+The 
+.i i th 
+argument to the function just called can be accessed as (arg \fIi\fP).
+To leave the trace loop, just type ^D or (tracereturn)
+and execution will continue.
+Note that ^D will work only on UNIX systems.
+.Tf "(foo if expression)"
+when foo is entered and the expression evaluates to non-nil, then the
+trace information will be printed for both exit and entry.
+If expression evaluates to nil, then no trace information will be
+printed.
+.Tf "(foo ifnot expression)"
+when foo is entered and the expression evaluates to nil, then the
+trace information will be printed for both entry and exit.
+If both \fBif\fP and 
+.b ifnot 
+are specified, then the 
+.b if 
+expression must evaluate
+to non nil AND the 
+.b ifnot 
+expression must evaluate to nil for the trace
+information to be printed out.
+.Tf "(foo evalin expression)"
+when foo is entered and after the entry trace information is printed,
+expression will be evaluated. 
+Exit trace information will be printed when foo exits.
+.Tf "(foo evalout expression)"
+when foo is entered, entry trace information will be printed.
+When foo exits, and before the exit trace information is printed,
+expression will be evaluated.
+.Tf "(foo evalinout expression)"
+this has the same effect as (trace (foo evalin expression evalout expression)).
+.Tf "(foo lprint)"
+this tells 
+.i trace 
+to use the level printer when printing the arguments to
+and the result of  a call to foo.
+The level printer prints only the top levels of list structure. 
+Any structure
+below three levels is printed as a &.
+This allows you to trace functions with massive arguments or results.
+.sp 2v
+.pp
+The following trace options permit one to have greater control over each
+action which takes place when a function is traced.
+These options are only meant to be used by people who need special hooks
+into the trace package.
+Most people should skip reading this section.
+.in .75i
+.Tf "(foo traceenter tefunc)"
+this tells 
+.i trace 
+that the function to be called when foo is entered is 
+tefunc.
+tefunc should be a lambda of two arguments, the first argument will be 
+bound to the name of the function being traced, foo in this case.
+The second argument will be bound to the list of arguments to which 
+foo should be applied.
+The function tefunc should print some sort of "entering foo" message.
+It should not apply foo to the arguments, however. 
+That is done later on.
+.Tf "(foo traceexit txfunc)"
+this tells 
+.i trace 
+that the function to be called when foo is exited is
+txfunc.
+txfunc should be a lambda of two arguments, the first argument will be
+bound to the name of the function being traced, foo in this case.
+The second argument will be bound to the result of the call to foo.
+The function txfunc should print some sort of "exiting foo" message.
+.Tf "(foo evfcn evfunc)"
+this tells 
+.i trace 
+that the form evfunc should be evaluated to get the value
+of foo applied to its arguments.  
+This option is a bit different from the other special options since evfunc
+will usually be an expression, not just the name of a function, and that
+expression will be specific to the evaluation of function foo.
+The argument list to be applied will be available as T-arglist.
+.Tf "(foo printargs prfunc)"
+this tells 
+.i trace 
+to used prfunc to print the arguments  to be
+applied to the function foo.
+prfunc should be a lambda of one argument.
+You might want to use this option if you wanted a print function which could
+handle circular lists.
+This option will work only if you do not specify your own 
+.b traceenter 
+function.
+Specifying the option 
+.b lprint 
+is just a simple way of changing the printargs
+function to the level printer.
+.Tf "(foo printres prfunc)"
+this tells 
+.i trace 
+to use prfunc to print the result of evaluating foo.
+prfunc should be a lambda of one argument.
+This option will work only if you do not specify your own 
+.b traceexit 
+function.
+Specifying the option 
+.b lprint 
+changes printres to the level printer.
+.sp 2v
+.pp
+You may specify more than one option for each function traced.  
+For example:
+.sp 1v
+.ti .5i
+\fI(trace (foo if\ (eq 3 (arg 1)) break lprint) (bar evalin (print xyzzy)))\fP
+.sp 1v
+This tells 
+.i trace 
+to trace two more functions, foo and bar.
+Should foo be called with the first argument 
+.i eq
+to 3, then the entering foo message will be printed with the level printer.
+Next it will enter a trace break loop, allowing you to evaluate any 
+lisp expressions.
+When you exit the trace break loop, foo will be applied to its arguments
+and the resulting value will be printed, again using the level printer.
+Bar is also traced, and each time bar is entered, an entering bar message
+will be printed and then the value of xyzzy will be printed.
+Next bar will be applied to its arguments and the result will be printed.
+If you tell 
+.i trace 
+to trace a function which is already traced, it will first
+.i untrace 
+it.  Thus if you want to specify more than one trace option for
+a function, you must do it all at once.
+The following is 
+.i not 
+equivalent to the preceding call to 
+.i trace 
+for foo:
+.sp 1v
+\fI(trace (foo if (eq 3 (arg 1))) (foo break) (foo lprint))\fP
+.sp 1v.
+In this example, only the last option, lprint, will be in effect.
+.pp
+If the symbol $tracemute is given a non nil value, printing of the 
+function name and arguments on entry and exit will be surpressed.
+This is particularly useful if the function you are tracing fails
+after many calls to it.  In this case you would tell 
+.i trace 
+to
+trace the function, set $tracemute to t, and begin the computation.
+When an error occurs you can use
+.i tracedump
+to print out the current trace frames.
+.pp
+Generally the trace package has its own internal names for the the lisp
+functions it uses, so that you can feel free to trace system functions like
+.i cond 
+and not worry about adverse interaction with the actions of the trace
+package.
+You can trace any type of function: lambda, nlambda, lexpr or macro whether
+compiled or interpreted and you can even trace array references (however
+you should not attempt to store in an array which has been traced).
+.pp
+When tracing compiled code keep in mind that many function calls are translated 
+directly to machine language  or other equivalent  function calls.
+A full list of open coded functions is listed at the beginning of the 
+liszt compiler source.
+.i Trace 
+will do a \fI(sstatus\ translink\ nil)\fP to insure that the 
+new traced definitions it defines are called instead of the old untraced ones.
+You may notice that compiled code will run slower after this is done.
+.Lf traceargs "s_func [x_level]"
+.Wh
+if x_level is missing it is assumed to be 1.
+.Re
+the arguments to the x_level\fIth\fP call to traced
+function s_func are returned.
+.Lf tracedump ""
+.Se
+the currently active trace frames are printed on the terminal.
+returns a list of functions untraced.
+.Lf untrace "[s_arg1 ...]"
+.Re
+a list of the functions which were untraced.
+.No
+if no arguments are given, all functions are untraced.
+.Se
+the old function definitions of all 
+traced functions are restored
+except in the case where it appears that 
+the current definition of a function was not created by trace.
diff --git a/usr/lisp/ch2.n b/usr/lisp/ch2.n
new file mode 100644 (file)
index 0000000..dbba368
--- /dev/null
@@ -0,0 +1,1526 @@
+." $Header: ch2.n 1.7 83/07/30 14:42:38 layer Exp $
+.Lc Data\ Structure\ Access 2
+.pp
+The following functions allow one to create and manipulate the various types
+of lisp data structures.
+Refer to \(sc1.2 for details of the data structures known to 
+.Fr .
+.sh 2 Lists \n(ch 1
+.pp
+The following functions exist for the creation and manipulating of lists.
+Lists are composed of a linked list of objects called 
+either 'list cells', 'cons cells' or 'dtpr cells'.
+Lists are normally terminated with the special symbol 
+.b nil .
+.b nil 
+is both a symbol and a representation for the empty list ().
+.sh 3 list\ creation
+.Lf cons "'g_arg1 'g_arg2"
+.Re
+a new list cell whose car is g_arg1 and whose cdr is g_arg2.
+.Lf xcons "'g_arg1 'g_arg2"
+.Eq
+\fI(cons 'g_arg2 'g_arg1)\fP
+.Lf ncons "'g_arg"
+.Eq 
+\fI(cons 'g_arg nil)\fP
+.Lf list "['g_arg1 ... ]"
+.Re
+a list whose elements are the g_arg\fIi\fP.
+.Lf append "'l_arg1 'l_arg2"
+.Re
+a list containing the elements of l_arg1 followed by l_arg2.
+.No
+To generate the result, the top level list cells of l_arg1 are duplicated
+and the cdr of the last list cell is set to point to l_arg2.
+Thus this is an expensive operation if l_arg1 is large.
+See the descriptions of 
+.i nconc 
+and 
+.i tconc 
+for cheaper ways of doing the 
+.i append 
+if the list l_arg1 can be altered.
+.Lf append1 "'l_arg1 'g_arg2"
+.Re
+a list like l_arg1 with g_arg2 as the last element.
+.No
+this is equivalent to (append 'l_arg1 (list 'g_arg2)).
+.Eb
+; A common mistake is using append to add one element to the end of a list
+\-> \fI(append '(a b c d) 'e)\fP
+(a b c d . e)
+; The user intended to say:
+\-> \fI(append '(a b c d) '(e))
+(a b c d e)
+; better is append1
+\-> \fI(append1 '(a b c d) 'e)\fP
+(a b c d e)
+.Ee
+.Lf quote! "[g_qform\fIi\fP] ...[! 'g_eform\fIi\fP] ...  [!! 'l_form\fIi\fP] ..."
+.Re
+The list resulting from the  splicing and insertion process 
+described below.
+.No
+.i quote!
+is the complement of the
+.i list
+function.  
+.i list
+forms a list by evaluating each for in the argument list; evaluation is
+suppressed if the form is \fIquote\fPed.  In 
+.i quote!,
+each form is implicitly \fIquote\fPed.  To be evaluated, a form
+must be preceded by one of the evaluate operations ! and !!. ! g_eform
+evaluates g_form and the value is inserted in the place of the call;
+!! l_form evaluates l_form and the value is spliced into the place of
+the call.
+.br
+.sp
+`Splicing in' means that the parentheses surrounding the list are removed
+as the example below shows.
+Use of the evaluate operators can occur at any level in a
+form argument.
+.br
+.sp
+Another way to get the effect of the \fIquote!\fP function is to use
+the backquote character macro (see \(sc 8.3.3).
+.Eb
+\fI(quote! cons ! (cons 1 2) 3) = (cons (1 . 2) 3)\fP
+\fI(quote! 1 !! (list 2 3 4) 5) = (1 2 3 4 5)\fP
+\fI(setq quoted 'evaled)(quote! ! ((I am  ! quoted))) = ((I am evaled))\fP
+\fI(quote! try ! '(this ! one)) = (try (this ! one))\fP
+.Ee
+
+.Lf bignum-to-list "'b_arg"
+.Re
+A list of the fixnums which are used to represent the bignum.
+.No
+the inverse of this function is
+.i list-to-bignum.
+.Lf list-to-bignum "'l_ints"
+.Wh
+l_ints is a list of fixnums.
+.Re
+a bignum constructed of the given fixnums.
+.No
+the inverse of this function is
+.i bignum-to-list.
+
+.sh 3 list\ predicates 
+.Lf dtpr "'g_arg"
+.Re
+t iff g_arg is a list cell.
+.No
+that (dtpr '()) is nil.
+.Lf listp "'g_arg"
+.Re
+t iff g_arg is a list object or nil.
+.Lf tailp "'l_x 'l_y"
+.Re
+l_x, if a list cell
+.i eq
+to l_x is found by
+.i cdr ing
+down l_y zero or more times, nil otherwise.
+.Eb
+\-> \fI(setq x '(a b c d) y (cddr x))\fP
+(c d)
+\-> \fI(and (dtpr x) (listp x))\fP     ; x and y are dtprs and lists
+t
+\-> \fI(dtpr '())\fP           ; () is the same as nil and is not a dtpr
+nil
+\-> \fI(listp '())\fP          ; however it is a list
+t
+\-> \fI(tailp y x)\fP
+(c d)
+.Ee
+.Lf length "'l_arg"
+.Re
+the number of elements in the top level of list l_arg.
+.sh 3 list\ accessing
+.Lf car "'l_arg"
+.Lx cdr "'l_arg"
+.Re the appropriate part of
+.i cons
+cell.
+(\fIcar\fP (\fIcons\fP x y)) is always x,
+(\fIcdr\fP (\fIcons\fP x y)) is always y.
+In
+.Fr ,
+the cdr portion is located first in memory.
+This is hardly noticeable, and seems to bother few.
+.Lf c\.\.r "'lh_arg"
+.Wh 
+the .. represents any positive number of \fBa\fP's and \fBd\fP's.
+.Re
+the result of accessing the list structure in the way determined by
+the function name.
+The \fBa\fP's and \fBd\fP's are read from right to left, a 
+.b d
+directing the access down the cdr part of the list cell and an
+.b a
+down the car part.
+.No
+lh_arg may also be nil, and it is guaranteed that the car and cdr of nil
+is nil.
+If lh_arg is a hunk, then \fI(car\ 'lh_arg)\fP is the same as 
+\fI(cxr\ 1\ 'lh_arg)\fP and  \fI(cdr\ 'lh_arg)\fP is the same
+as \fI(cxr\ 0\ 'lh_arg)\fP.
+.br
+It is generally hard to read and understand the context
+of functions with large strings of 
+.b a 's
+and
+.b d 's,
+but these functions are supported by rapid accessing and open-compiling
+(see Chapter 12).
+.Lf nth "'x_index 'l_list"
+.Re
+the nth element of l_list, assuming zero-based index.
+Thus (nth 0 l_list) is the same as (car l_list).
+.i nth
+is both a function, and a compiler macro, so that
+more efficient code might be generated than for
+.i nthelem
+(described below).
+.No
+If x_arg1 is non-positive or greater than the length
+of the list, nil is returned. 
+.Lf nthcdr "'x_index 'l_list"
+.Re
+the result of \fIcdr\fPing down the list l_list x_index times.
+.No
+If x_index is less than 0, then \fI(cons\ nil\ 'l_list)\fP is returned.
+.Lf nthelem "'x_arg1 'l_arg2"
+.Re
+The x_arg1'\fIst\fP element of the list l_arg2.
+.No
+This function comes from the PDP-11 lisp system.
+.Lf last "'l_arg"
+.Re
+the last list cell in the list l_arg.
+.Ex
+\fIlast\fP does NOT return the last element of a list!
+.br
+\fI(last '(a b))\fP = (b)
+.Lf ldiff "'l_x 'l_y"
+.Re
+a  list  of all
+elements in l_x but not in l_y
+, i.e., the list difference of
+l_x and l_y.
+.No
+l_y must be a tail of l_x, i.e.,
+.i eq
+to the result of applying some number of \fIcdr\fP's
+to l_x.  
+Note  that  the  value  of  \fIldiff\fP  is  always  new  list
+structure unless l_y is nil, in which case \fI(ldiff l_x nil)\fP is l_x
+itself.
+If l_y  is  not  a  tail  of  l_x, \fIldiff\fP generates an error.
+.Ex
+\fI(ldiff 'l_x (member 'g_foo 'l_x))\fP gives all elements
+in l_x up to the first g_foo.
+.sh 3 list\ manipulation
+.Lf rplaca "'lh_arg1 'g_arg2"
+.Re
+the modified lh_arg1.
+.Se
+the car of lh_arg1 is set to  g_arg2.
+If lh_arg1 is a hunk then the second element of the hunk is set to g_arg2.
+.Lf rplacd "'lh_arg1 'g_arg2"
+.Re
+the modified lh_arg1.
+.Se
+the cdr of lh_arg2 is set to g_arg2.
+If lh_arg1 is a hunk then the first element of the hunk is set to g_arg2.
+
+.Lf attach "'g_x 'l_l"
+.Re
+l_l whose 
+.i car
+is now g_x, whose 
+.i cadr 
+is the original \fI(car\ l_l)\fP, 
+and whose 
+.i cddr 
+is the original \fI(cdr\ l_l)\fP.
+.No
+what happens is that g_x is added to the 
+beginning of list l_l  yet maintaining the same list cell  at the 
+beginning of the list.
+.Lf delete "'g_val 'l_list ['x_count]"
+.Re
+the result of splicing g_val from the top level of
+l_list no more than x_count times.
+.No
+x_count defaults to a very large number, thus if x_count is not given, all
+occurrences of g_val are removed from the top level of l_list.
+g_val is compared with successive 
+.i car 's
+of l_list using the function
+.i equal .
+.Se
+l_list is modified using rplacd, no new list cells are used.
+.Lf delq "'g_val 'l_list ['x_count]"
+.Lx dremove "'g_val 'l_list ['x_count]"
+.Re
+the result of splicing g_val from the top level of l_list no more than
+x_count times.
+.No
+.i delq 
+(and 
+.i dremove )
+are the same as 
+.i delete 
+except that 
+.i eq
+is used for comparison instead of 
+.i equal .
+.Eb
+; note that you should use the value returned by \fIdelete\fP or \fIdelq\fP
+; and not assume that g_val will always show the deletions.
+; For example
+
+\-> \fI(setq test '(a b c a d e))\fP
+(a b c a d e)
+\-> \fI(delete 'a test)\fP
+(b c d e)         ; the value returned is what we would expect 
+\-> \fItest\fP
+(a b c d e)       ; but test still has the first a in the list!
+.Ee
+.Lf remq "'g_x 'l_l ['x_count]"
+.Lx remove "'g_x 'l_l"
+.Re
+a 
+.i copy
+of l_l with all top level elements
+.i equal
+to g_x removed.
+.i remq
+uses 
+.i eq
+instead of
+.i equal
+for comparisons.
+.No
+remove does not modify its arguments like 
+.i delete ,
+and
+.i delq 
+do.
+.Lf insert "'g_object 'l_list 'u_comparefn 'g_nodups"
+.Re
+a list consisting of l_list with g_object destructively inserted
+in a place determined by the ordering function u_comparefn.
+.No
+\fI(comparefn 'g_x 'g_y)\fP
+should return something non-nil if g_x can precede g_y in sorted order,
+nil if g_y must precede g_x.
+If u_comparefn is nil, alphabetical order
+will be used.  
+If g_nodups is non-nil, an element will not be inserted if an
+equal element is already in the list.
+.i insert
+does binary search to determine where to insert the new element.
+.Lf merge "'l_data1 'l_data2 'u_comparefn"
+.Re
+the merged list of the two input sorted lists l_data1 and l_data1
+using binary comparison function u_comparefn.  
+.No
+\fI(comparefn 'g_x 'g_y)\fP
+should return something non-nil if g_x can precede g_y in sorted order,
+nil if g_y must precede g_x.  If u_comparefn is nil, 
+alphabetical order
+will be used.  u_comparefn should be thought of as "less than or equal".
+.i merge
+changes both of its data arguments.
+.Lf subst "'g_x 'g_y 'l_s"
+.Lx dsubst "'g_x 'g_y 'l_s"
+.Re
+the result of substituting g_x for all 
+.i equal
+occurrences of g_y  at all levels in l_s.  
+.No
+If g_y is a symbol, 
+.i eq
+will be used for comparisons.
+The function
+.i subst
+does not modify l_s 
+but the function
+.i dsubst
+(destructive substitution)
+does.
+.Lf lsubst "'l_x 'g_y 'l_s"
+.Re
+a copy of l_s  with l_x spliced in for every occurrence of of g_y 
+at all levels. 
+Splicing in means that the parentheses surrounding the list l_x are removed
+as the example below shows.
+.Eb
+\-> \fI(subst '(a b c) 'x '(x y z (x y z) (x y z)))\fP
+((a b c) y z ((a b c) y z) ((a b c) y z))
+\-> \fI(lsubst '(a b c) 'x '(x y z (x y z) (x y z)))\fP
+(a b c y z (a b c y z) (a b c y z))
+.Ee
+.Lf subpair "'l_old 'l_new 'l_expr"
+.Wh
+there are  the same number of elements in l_old as l_new.
+.Re
+the list l_expr with all occurrences of a object in l_old replaced by
+the corresponding one in l_new.
+When a substitution is made, a copy of the value to substitute in 
+is not made.
+.Ex
+\fI(subpair '(a c)' (x y) '(a b c d)) = (x b y d)\fP
+
+.Lf nconc "'l_arg1 'l_arg2 ['l_arg3 ...]"
+.Re
+A list consisting of the elements of l_arg1 followed by the elements of
+l_arg2 followed by l_arg3 and so on.
+.No
+The 
+.i cdr 
+of the last list cell of l_arg\fIi\fP is changed to point to 
+l_arg\fIi+1\fP.
+.Eb 
+; \fInconc\fP is faster than \fIappend\fP because it doesn't allocate new list cells. 
+\-> \fI(setq lis1 '(a b c))\fP
+(a b c)
+\-> \fI(setq lis2 '(d e f))\fP
+(d e f)
+\-> \fI(append lis1 lis2)\fP
+(a b c d e f)
+\-> \fIlis1\fP
+(a b c)       ; note that lis1 has not been changed by \fIappend\fP
+\-> \fI(nconc lis1 lis2)\fP
+(a b c d e f) ; \fInconc\fP returns the same value as \fIappend\fP
+\-> \fIlis1\fP
+(a b c d e f) ; but in doing so alters lis1
+.Ee
+
+.Lf reverse "'l_arg"
+.Lx nreverse "'l_arg"
+.Re
+the list l_arg with the elements at the top
+level in reverse  order.
+.No
+The function
+.i nreverse
+does the reversal in place,
+that is the list structure is modified.
+.Lf nreconc "'l_arg 'g_arg"
+.Eq
+\fI(nconc (nreverse 'l_arg) 'g_arg)\fP
+
+.sh 2 Predicates
+.pp
+The following functions test for properties of data objects.  
+When the result of the test is either 'false' or 'true', then
+\fBnil\fP will be returned for 'false' and something other than
+\fBnil\fP (often \fBt\fP) will be returned for 'true'.
+.Lf arrayp "'g_arg"
+.Re
+t iff g_arg is of type array.
+.Lf atom "'g_arg"
+.Re
+t iff g_arg is not a list or hunk object.
+.No
+\fI(atom '())\fP returns t.
+.Lf bcdp "'g_arg"
+.Re
+t iff g_arg is a data object of type binary.
+.No
+the name of this function is a throwback to the PDP-11 Lisp system.
+.Lf bigp "'g_arg"
+.Re
+t iff g_arg is a bignum.
+.Lf dtpr "'g_arg"
+.Re
+t iff g_arg is a list cell.
+.No
+that (dtpr '()) is nil.
+.Lf hunkp "'g_arg"
+.Re
+t iff g_arg is a hunk.
+.Lf listp "'g_arg"
+.Re
+t iff g_arg is a list object or nil.
+.Lf stringp "'g_arg"
+.Re
+t iff g_arg is a string.
+.Lf symbolp "'g_arg"
+.Re
+t iff g_arg is a symbol.
+.Lf valuep "'g_arg"
+.Re
+t iff g_arg is a value cell
+.Lf vectorp 'v_vector
+.Re
+\fBt\fP iff the argument is a vector.
+.Lf vectorip 'v_vector
+.Re
+\fBt\fP iff the argument is an immediate-vector.
+.Lf type "'g_arg"
+.Lx typep "'g_arg"
+.Re
+a symbol whose pname describes the type of g_arg.
+.Lf signp "s_test 'g_val"
+.Re
+t iff g_val is a number  and the given test s_test on g_val returns true.
+.No
+The fact that 
+.i signp
+simply returns nil if g_val is not a number is probably the most
+important reason that 
+.i signp
+is used.
+The permitted values for s_test and what they mean are given in this table.
+.TS
+center box;
+l l .
+s_test tested
+
+=
+l      g_val < 0
+le     g_val \(<= 0
+e      g_val = 0
+n      g_val \(!= 0
+ge     g_val \(>= 0
+g      g_val > 0
+.TE
+.Lf eq "'g_arg1 'g_arg2"
+.Re
+t if g_arg1 and g_arg2 are the exact same lisp object.
+.No
+.i Eq
+simply tests if g_arg1 and g_arg2 are located in the exact same
+place in memory.
+Lisp objects which print the same are not necessarily 
+.i eq .
+The only objects guaranteed to be 
+.i eq
+are interned symbols with the same print name.
+[Unless a symbol is created in a special way (such as with
+.i uconcat 
+or 
+.i maknam )
+it will be interned.]
+.Lf neq "'g_x 'g_y"
+.Re
+t if g_x is not 
+.i eq
+to g_y, otherwise nil.
+.Lf equal "'g_arg1 'g_arg2"
+.Lx eqstr "'g_arg1 'g_arg2"
+.Re
+t iff g_arg1 and g_arg2 have the same structure as described below.
+.No
+g_arg and g_arg2 are 
+.i equal
+if
+.np
+they are \fIeq\fP.
+.np
+they are both fixnums with the same value
+.np
+they are both flonums with the same value
+.np
+they are both bignums with the same value
+.np
+they are both strings and are identical.
+.np
+they are both lists and their cars and cdrs are
+.i equal .
+.Eb
+; \fIeq\fP is much faster than \fIequal\fP, especially in compiled code,
+; however you cannot use \fIeq\fP to test for equality of numbers outside
+; of the range -1024 to 1023.  \fIequal\fP will always work.
+\-> \fI(eq 1023 1023)\fP
+t
+\-> \fI(eq 1024 1024)\fP
+nil
+\-> \fI(equal 1024 1024)\fP
+t
+.Ee
+
+.Lf not "'g_arg"
+.Lx null "'g_arg"
+.Re
+t iff g_arg is nil.
+
+.Lf member "'g_arg1 'l_arg2"
+.Lx memq "'g_arg1 'l_arg2"
+.Re
+that part of the l_arg2 beginning with the first occurrence
+of g_arg1.
+If g_arg1 is not in the top level of l_arg2, nil is returned.
+.No
+.i member 
+tests for equality with 
+.i equal ,
+.i memq 
+tests for equality with 
+.i eq .
+
+.sh 2 Symbols\ and\ Strings
+.pp
+In many of the following functions the distinction between symbols and
+strings is somewhat blurred.
+To remind ourselves of the difference,
+a string is a null terminated sequence of characters, stored as
+compactly as possible.
+Strings are used as constants in
+.Fr .
+They
+.i eval
+to themselves.
+A symbol has additional structure:
+a value, property list, function binding,
+as well as its external representation (or print-name).
+If a symbol is given to one of the string manipulation functions below, its
+print name will be used.
+.pp
+Another popular way to represent strings in Lisp is as a list of fixnums
+which represent characters.
+The suffix 'n' to a string manipulation function indicates that it 
+returns a string in this form.
+.sh 3 symbol\ and\ string\ creation
+.Lf concat "['stn_arg1 ... ]"
+.Lx uconcat "['stn_arg1 ... ]"
+.Re
+a symbol whose print name
+is the result of concatenating the print names,
+string characters or numerical representations
+of the sn_arg\fIi\fP.
+.No
+If no arguments are given, a symbol with a null pname is returned.
+\fIconcat\fP places the symbol created on the oblist, the function 
+.i uconcat
+does the same thing but does not place the new symbol on the oblist.
+.Ex
+\fI(concat 'abc (add 3 4) "def")\fP = abc7def
+.Lf concatl "'l_arg"
+.Eq
+\fI(apply 'concat 'l_arg)\fP
+
+.Lf implode "'l_arg"
+.Lx maknam "'l_arg"
+.Wh
+l_arg is a list of symbols, strings and small fixnums.
+.Re
+The symbol whose print name is the result of concatenating the 
+first characters of the print names of the symbols and strings
+in the list.
+Any fixnums are converted to the equivalent ascii character.
+In order to concatenate entire strings or print names, use the
+function
+.i concat .
+.No
+.i implode 
+interns the symbol it creates,
+.i maknam 
+does not.
+.Lf gensym "['s_leader]"
+.Re
+a new uninterned atom beginning with the first character of s_leader's
+pname, or beginning with g if s_leader is not given.
+.No
+The symbol looks like x0nnnnn where x is s_leader's first character and
+nnnnn is the number of times you have called gensym.
+.Lf copysymbol "'s_arg 'g_pred"
+.Re
+an uninterned symbol with the same print name as s_arg.
+If g_pred is non nil, then the value, function binding
+and property list of the new symbol are made 
+.i eq 
+to those of s_arg.
+
+.Lf ascii "'x_charnum"
+.Wh
+x_charnum is between 0 and 255.
+.Re
+a symbol whose print name is the single character whose fixnum 
+representation is x_charnum.
+
+.Lf intern "'s_arg"
+.Re
+s_arg
+.Se
+s_arg is put on the oblist if it is not already there.
+.Lf remob "'s_symbol"
+.Re
+s_symbol
+.Se
+s_symbol is removed from the oblist.
+.Lf rematom "'s_arg"
+.Re
+t if s_arg is indeed an atom.
+.Se
+s_arg is put on the free atoms list, effectively reclaiming an
+atom cell.
+.No
+This function does 
+.i not
+check to see if s_arg is on the oblist or is referenced anywhere.
+Thus calling 
+.i rematom
+on an atom in the oblist may result in disaster when that atom cell
+is reused!
+.sh 3 string\ and\ symbol\ predicates
+.Lf boundp "'s_name"
+.Re
+nil  if s_name is unbound, that is it has never be given a value.
+If x_name has the value g_val, then (nil\ .\ g_val) is returned.
+.Lf alphalessp "'st_arg1 'st_arg2"
+.Re
+t iff the `name' of st_arg1 is alphabetically less than the 
+name of st_arg2.  
+If st_arg is a symbol then its `name' is its print name.
+If st_arg is a string, then its `name' is the string itself.
+.sh 3 symbol\ and\ string\ accessing
+.Lf symeval "'s_arg"
+.Re
+the value of symbol s_arg.
+.No
+It is illegal to ask for the value of an unbound symbol.
+This function has the same effect as
+.i eval ,
+but compiles into much more efficient code.
+.Lf get_pname "'s_arg"
+.Re
+the string which is the print name of s_arg.
+.Lf plist "'s_arg"
+.Re
+the property list of s_arg.
+.Lf getd "'s_arg"
+.Re
+the function definition of s_arg or nil if there is no function definition.
+.No
+the function definition may turn out to be an array header.
+.Lf getchar "'s_arg 'x_index"
+.Lx nthchar "'s_arg 'x_index"
+.Lx getcharn "'s_arg 'x_index"
+.Re
+the x_index\fIth\fP character of the print name of s_arg or nil if x_index
+is less than 1 or greater than the length of s_arg's print name.
+.No
+.i getchar 
+and 
+.i nthchar 
+return a symbol with a single character print name,
+.i getcharn 
+returns the fixnum representation of the character.
+.Lf substring "'st_string 'x_index ['x_length]"
+.Lx substringn "'st_string 'x_index ['x_length]"
+.Re
+a string of length at most
+x_length starting at x_index\fIth\fP character
+in the string.
+.No
+If x_length is not given, all of the characters for x_index
+to the end of the string are returned.
+If x_index is negative the string begins at the
+x_index\fIth\fP character from the end.
+If x_index is out of bounds, nil is returned.
+.No
+.i substring 
+returns a list of symbols, 
+.i substringn 
+returns a list of fixnums.
+If 
+.i substringn 
+is given a 0 x_length argument then a single fixnum 
+which is the x_index\fIth\fP character is returned.
+.sh 3 symbol\ and\ string\ manipulation
+.Lf set "'s_arg1 'g_arg2"
+.Re
+g_arg2.
+.Se
+the value of s_arg1 is set to g_arg2.
+.Lf setq "s_atm1 'g_val1 [ s_atm2 'g_val2 ... ... ]"
+.Wh
+the arguments are pairs of atom names and expressions.
+.Re
+the last g_val\fIi\fP.
+.Se
+each s_atm\fIi\fP is set to have the value g_val\fIi\fP.
+.No
+.i set
+evaluates all of its arguments,
+.i setq
+does not evaluate the s_atm\fIi\fP.
+.Lf desetq "sl_pattern1 'g_exp1 [... ...]"
+.Re
+g_expn
+.Se
+This acts just like \fIsetq\fP if all the sl_pattern\fIi\fP are symbols.
+If sl_pattern\fIi\fP is a list then it  is a template which should
+have the same structure as g_exp\fIi\fP
+The symbols in sl_pattern are assigned to the corresponding 
+parts of g_exp.
+.Ex
+\fI(desetq (a b (c . d)) '(1 2 (3 4 5)))\fP
+.br
+sets a to 1, b to 2, c to 3, and d to (4 5).
+
+.Lf setplist "'s_atm 'l_plist"
+.Re
+l_plist.
+.Se
+the property list of s_atm is set to l_plist.
+.Lf makunbound "'s_arg"
+.Re
+s_arg
+.Se
+the value of s_arg is made `unbound'.
+If the interpreter attempts to evaluate s_arg before it is again 
+given a value, an unbound variable error will occur.
+.Lf aexplode "'s_arg"
+.Lx explode  "'g_arg"
+.Lx aexplodec "'s_arg"
+.Lx explodec "'g_arg"
+.Lx aexploden "'s_arg"
+.Lx exploden "'g_arg"
+.Re
+a list of the characters used to print out s_arg or g_arg.
+.No
+The functions beginning with 'a' are internal functions which are limited
+to symbol arguments.  
+The functions 
+.i aexplode 
+and 
+.i explode
+return a list of characters which 
+.i print
+would use to print the argument.  
+These characters include all necessary escape characters.
+Functions 
+.i aexplodec 
+and
+.i explodec
+return a list of characters which
+.i patom
+would use to print the argument (i.e. no escape characters).
+Functions 
+.i aexploden 
+and 
+.i exploden
+are similar to 
+.i aexplodec 
+and 
+.i explodec 
+except that a list of fixnum equivalents of characters are returned.
+.Eb
+\-> \fI(setq x '|quote this \e| ok?|)\fP
+|quote this \e| ok?|
+\-> \fI(explode x)\fP
+(q u o t e |\e\e| | | t h i s |\e\e| | | |\e\e| |\e|| |\e\e| | | o k ?)
+; note that |\e\e| just means the single character: backslash.
+; and |\e|| just means the single character: vertical bar
+; and | | means the single character: space
+
+\-> \fI(explodec x)\fP
+(q u o t e | | t h i s | | |\e|| | | o k ?)
+\-> \fI(exploden x)\fP
+(113 117 111 116 101 32 116 104 105 115 32 124 32 111 107 63)
+.Ee
+.sh 2 Vectors
+.pp
+See Chapter 9 for a discussion of vectors.
+They are intermediate in efficiency between arrays and hunks.
+.sh 3 vector\ creation
+.Lf new-vector "'x_size ['g_fill ['g_prop]]"
+.Re
+A \fBvector\fP of length x_size.
+Each data entry is initialized to g_fill, or to nil, if the argument g_fill
+is not present.
+The vector's property is set to g_prop, or to nil, by default.
+.Lf new-vectori-byte "'x_size ['g_fill ['g_prop]]"
+.Lx new-vectori-word "'x_size ['g_fill ['g_prop]]"
+.Lx new-vectori-long "'x_size ['g_fill ['g_prop]]"
+.Re
+A \fBvectori\fP with x_size elements in it.
+The actual memory requirement is two long words + x_size*(n bytes),
+where n is 1 for new-vector-byte, 2 for new-vector-word, or 4 for
+new-vectori-long.
+Each data entry is initialized to g_fill, or to zero, if the argument g_fill
+is not present.
+The vector's property is set to g_prop, or nil, by default.
+.sp 2v
+.lp
+Vectors may be created by specifying multiple initial values:
+.Lf vector "['g_val0 'g_val1 ...]"
+.Re
+a \fBvector\fP, with as many data elements as there are arguments.
+It is quite possible to have a vector with no data elements.
+The vector's property will be null.
+.Lf vectori-byte "['x_val0 'x_val2 ...]"
+.Lx vectori-word "['x_val0 'x_val2 ...]"
+.Lx vectori-long "['x_val0 'x_val2 ...]"
+.Re
+a \fBvectori\fP, with as many data elements as there are arguments.
+The arguments are required to be fixnums.
+Only the low order byte or word is used in the case of vectori-byte
+and vectori-word.
+The vector's property will be null.
+.sh 3 vector\ reference
+.Lf vref "'v_vect 'x_index"
+.Lx vrefi-byte "'V_vect 'x_bindex"
+.Lx vrefi-word "'V_vect 'x_windex"
+.Lx vrefi-long "'V_vect 'x_lindex"
+.Re
+the desired data element from a vector.
+The indices must be fixnums.
+Indexing is zero-based.
+The vrefi functions sign extend the data.
+.Lf vprop 'Vv_vect
+.Re
+The Lisp property associated with a vector.
+.Lf vget "'Vv_vect 'g_ind"
+.Re
+The value stored under g_ind if the Lisp property associated
+with 'Vv_vect is a disembodied property list.
+.Lf vsize 'Vv_vect
+.Lx vsize-byte 'V_vect
+.Lx vsize-word 'V_vect
+.Re
+the number of data elements in the vector.  For immediate-vectors,
+the functions vsize-byte and vsize-word return the number of data elements,
+if one thinks of the binary data as being comprised of bytes or words.
+.sh 3 vector\ modfication
+.Lf vset "'v_vect 'x_index 'g_val"
+.Lx vseti-byte "'V_vect 'x_bindex 'x_val"
+.Lx vseti-word "'V_vect 'x_windex 'x_val"
+.Lx vseti-long "'V_vect 'x_lindex 'x_val"
+.Re
+the datum.
+.Se
+The indexed element of the vector is set to the value.
+As noted above, for vseti-word and vseti-byte, the index
+is construed as the number of the data element within
+the vector.  It is not a byte address.
+Also, for those two functions,
+the low order byte or word of x_val is what is stored.
+.Lf vsetprop "'Vv_vect 'g_value"
+.Re
+g_value.  This should be either a symbol
+or a disembodied property list whose
+.i car
+is a symbol identifying the type of
+the vector.
+.Se
+the property list of Vv_vect is set to g_value.
+.Lf vputprop "'Vv_vect 'g_value 'g_ind"
+.Re
+g_value.
+.Se
+If the vector property of Vv_vect is a disembodied property list,
+then vputprop adds the value g_value under the indicator g_ind.
+Otherwise, the old vector property is made the first
+element of the list.
+.sh 2 Arrays
+.pp
+See Chapter 9 for a complete description of arrays.
+Some of these functions are part of a Maclisp array
+compatibility package, which represents only one simple way of using the
+array structure of
+.Fr .
+.sh 3 array\ creation
+.Lf marray  "'g_data 's_access 'g_aux 'x_length 'x_delta"
+.Re
+an array type with the fields set up from the above arguments
+in the obvious way (see \(sc 1.2.10).
+.Lf *array "'s_name 's_type 'x_dim1 ... 'x_dim\fIn\fP"
+.Lx array "s_name s_type x_dim1 ... x_dim\fIn\fP"
+.Wh
+s_type may be one of t, nil, fixnum, flonum, fixnum-block and 
+flonum-block.
+.Re
+an array of type s_type with n dimensions of extents given by the 
+x_dim\fIi\fP.
+.Se
+If s_name is non nil, the function definition of s_name is
+set to the array structure returned.
+.No
+These 
+functions create a Maclisp compatible array.
+In 
+.Fr
+arrays of type t, nil, fixnum and flonum are equivalent and the elements
+of these arrays can be any type of lisp object.
+Fixnum-block and flonum-block arrays are restricted to fixnums and flonums
+respectively and are used mainly to communicate with 
+foreign functions (see \(sc8.5).
+.No
+.i *array 
+evaluates its arguments, 
+.i array
+does not.
+.sh 3 array\ predicate
+.Lf arrayp "'g_arg"
+.Re
+t iff g_arg is of type array.
+.sh 3 array\ accessors
+
+.Lf getaccess "'a_array"
+.Lx getaux "'a_array"
+.Lx getdelta "'a_array"
+.Lx getdata "'a_array"
+.Lx getlength "'a_array"
+.Re
+the field of the array object a_array given by the function name.
+.Lf arrayref "'a_name 'x_ind"
+.Re
+the x_ind\fIth\fP element of the array object a_name.
+x_ind of zero accesses the first element.
+.No
+.i arrayref
+uses the data, length and delta fields of a_name to determine which
+object to return.
+.Lf arraycall "s_type 'as_array 'x_ind1 ... "
+.Re
+the element selected by  the indicies from the array a_array
+of type s_type.
+.No
+If as_array is a symbol then the function binding of this symbol should
+contain an array object.
+.br
+s_type is ignored by
+.i arraycall
+but is included for compatibility with Maclisp.
+.Lf arraydims "'s_name"
+.Re
+a list of the type and bounds of the array s_name.
+.Lf listarray "'sa_array ['x_elements]"
+.Re
+a list of all of the elements in array sa_array.
+If x_elements
+is given, then only the first x_elements are returned.
+
+.Eb
+; We will create a 3 by 4 array of general lisp objects
+\-> \fI(array ernie t 3 4)\fP
+array[12]
+
+; the array header is stored in the function definition slot of the
+; symbol ernie
+\-> \fI(arrayp (getd 'ernie))\fP
+t
+\-> \fI(arraydims (getd 'ernie))\fP
+(t 3 4)
+
+; store in ernie[2][2] the list (test list)
+\-> \fI(store (ernie 2 2) '(test list))\fP
+(test list)
+
+; check to see if it is there
+\-> \fI(ernie 2 2)\fP
+(test list)
+
+; now use the low level function \fIarrayref\fP to find the same element
+; arrays are 0 based and row-major (the last subscript varies the fastest)
+; thus element [2][2] is the 10th element , (starting at 0).
+\-> \fI(arrayref (getd 'ernie) 10)\fP
+(ptr to)(test list)    ; the result is a value cell (thus the (ptr to))
+.Ee
+.sh 3 array\ manipulation
+.Lf putaccess "'a_array 'su_func"
+.Lx putaux "'a_array 'g_aux"
+.Lx putdata "'a_array 'g_arg"
+.Lx putdelta "'a_array 'x_delta"
+.Lx putlength "'a_array 'x_length"
+.Re
+the second argument to the function.
+.Se
+The field of the array object given by the function name is replaced
+by the second argument to the function.
+.Lf store "'l_arexp 'g_val"
+.Wh
+l_arexp is an expression
+which references an array element.
+.Re
+g_val
+.Se
+the array location which contains the element which l_arexp references is 
+changed to contain g_val.
+.Lf fillarray "'s_array 'l_itms"
+.Re
+s_array
+.Se
+the array s_array is filled with elements from l_itms.
+If there are not enough elements in l_itms to fill the entire array,
+then the last element of l_itms is used to fill the remaining parts
+of the array.
+.sh 2 Hunks
+.pp
+Hunks are vector-like objects whose size can range from 1 to 128 elements.
+Internally hunks are allocated in sizes which are powers of 2.
+In order to create hunks of a given size, 
+a hunk with at least that many elements is allocated
+and a distinguished symbol \s-2EMPTY\s0 is placed in those 
+elements not requested.
+Most hunk functions respect those distinguished symbols, but there are
+two 
+.i (*makhunk
+and
+.i *rplacx )
+which will overwrite the distinguished symbol.
+.sh 3 hunk\ creation
+.Lf hunk "'g_val1 ['g_val2 ... 'g_val\fIn\fP]"
+.Re
+a hunk of length n whose elements are initialized to the g_val\fIi\fP.
+.No
+the maximum size of a hunk is 128.
+.Ex
+\fI(hunk 4 'sharp 'keys)\fP = {4 sharp keys}
+.Lf makhunk "'xl_arg"
+.Re
+a hunk of length xl_arg initialized to all nils if xl_arg is a fixnum.
+If xl_arg is a list, then we return a hunk of size \fI(length\ 'xl_arg)\fP
+initialized to the elements in xl_arg.
+.No
+\fI(makhunk\ '(a\ b\ c))\fP is equivalent to \fI(hunk\ 'a\ 'b\ 'c)\fP.
+.Ex
+\fI(makhunk 4)\fP = \fI{nil nil nil nil}\fP
+.Lf *makhunk "'x_arg"
+.Re
+a hunk of size 2\*[x_arg\*] initialized to \s-2EMPTY\s0.
+.No
+This is only to be used by such functions as \fIhunk\fP and \fImakhunk\fP
+which create and initialize hunks for users.
+.sh 3 hunk\ accessor
+.Lf cxr "'x_ind 'h_hunk"
+.Re
+element x_ind (starting at 0) of hunk h_hunk.
+.Lf hunk-to-list 'h_hunk
+.Re
+a list consisting of the elements of h_hunk.
+.sh 3 hunk\ manipulators
+.Lf rplacx "'x_ind 'h_hunk 'g_val"
+.Lx *rplacx "'x_ind 'h_hunk 'g_val"
+.Re
+h_hunk
+.Se
+Element x_ind (starting at 0) of h_hunk is set to g_val.
+.No
+.i rplacx 
+will not modify one of the distinguished (EMPTY) elements
+whereas
+.i *rplacx 
+will.
+.Lf hunksize "'h_arg"
+.Re
+the size of the hunk h_arg.
+.Ex
+\fI(hunksize (hunk 1 2 3))\fP = 3
+.sh 2 Bcds
+.pp
+A bcd object contains a pointer to compiled code and to the type of 
+function object the compiled code represents.
+.Lf getdisc "'y_bcd"
+.Lx getentry "'y_bcd"
+.Re
+the field of the bcd object given by the function name. 
+.Lf putdisc "'y_func 's_discipline"
+.Re
+s_discipline
+.Se
+Sets the discipline field of y_func to s_discipline.
+.sh 2 Structures
+.pp
+There are three common structures constructed out of list cells: the
+assoc list, the property list and the tconc list.
+The functions below manipulate these structures.
+.sh 3 assoc\ list
+.pp
+An `assoc list' (or alist) is a common lisp data structure.  It has the
+form 
+.br
+.ce 1
+((key1 . value1) (key2 . value2) (key3 . value3) ... (keyn . valuen))
+.Lf assoc "'g_arg1 'l_arg2"
+.Lx assq "'g_arg1 'l_arg2"
+.Re
+the first top level element of l_arg2 whose
+.i car
+is 
+.i equal
+(with 
+.i assoc )
+or
+.i eq
+(with 
+.i assq )
+to g_arg1.
+.No
+Usually l_arg2 has an
+.i a-list
+structure and g_arg1 acts as key.
+.Lf sassoc "'g_arg1 'l_arg2 'sl_func"
+.Re 
+the result of \fI(cond\ ((assoc\ 'g_arg\ 'l_arg2)\ (apply\ 'sl_func\ nil)))\fP
+.No
+sassoc is written as a macro.
+.Lf sassq "'g_arg1 'l_arg2 'sl_func"
+.Re 
+the result of \fI(cond\ ((assq\ 'g_arg\ 'l_arg2)\ (apply\ 'sl_func\ nil)))\fP
+.No
+sassq is written as a macro.
+
+.Eb
+; \fIassoc\fP or \fIassq\fP is given a key and an assoc list and returns
+; the key and value item if it exists, they differ only in how they test
+; for equality of the keys.
+
+\-> \fI(setq alist '((alpha . a) ( (complex key) . b) (junk . x)))\fP
+((alpha . a) ((complex key) . b) (junk . x))
+
+; we should use \fIassq\fP when the key is an atom
+\-> \fI(assq 'alpha alist)\fP
+(alpha . a)
+
+; but it may not work when the key is a list
+\-> \fI(assq '(complex key) alist)\fP
+nil
+
+; however \fIassoc\fP will always work
+\-> \fI(assoc '(complex key) alist)\fP
+((complex key) . b)
+.Ee
+.Lf sublis "'l_alst 'l_exp"
+.Wh
+l_alst is an 
+.i a-list .
+.Re
+the list l_exp with every occurrence of key\fIi\fP replaced by val\fIi\fP.
+.No
+new list structure is returned to prevent modification of l_exp.
+When a substitution is made, a copy of the value to substitute in 
+is not made.
+.sh 3 property\ list
+.pp
+A property list consists of an alternating sequence of keys and
+values.  Normally a property list is stored on a symbol. A list
+is a 'disembodied' property list if it contains an odd number of
+elements, the first of which is ignored.
+.Lf plist "'s_name"
+.Re
+the property list of s_name.
+.Lf setplist "'s_atm 'l_plist"
+.Re
+l_plist.
+.Se
+the property list of s_atm is set to l_plist.
+
+.Lf get "'ls_name 'g_ind"
+.Re
+the value under indicator g_ind in ls_name's property list if ls_name
+is a symbol.
+.No
+If there is no indicator g_ind in ls_name's property list nil is returned.
+If ls_name is a list of an odd number of elements then it is a disembodied
+property list. 
+\fIget\fP searches a disembodied property list by starting at its 
+\fIcdr\fP, and comparing every other element with g_ind, using 
+\fIeq\fP.
+.Lf getl "'ls_name 'l_indicators"
+.Re
+the property list ls_name beginning at the first indicator which is
+a member of the list l_indicators, or nil if none of the indicators
+in l_indicators are on ls_name's property list.
+.No
+If ls_name is a list, then it is assumed to be a disembodied property
+list.
+
+.Lf putprop "'ls_name 'g_val 'g_ind"
+.Lx defprop "ls_name g_val g_ind"
+.Re
+g_val.
+.Se
+Adds to the property list of ls_name the value g_val under the indicator
+g_ind.
+.No
+.i putprop
+evaluates it arguments, 
+.i defprop
+does not.
+ls_name may be a disembodied property list, see \fIget\fP.
+.Lf remprop "'ls_name 'g_ind"
+.Re
+the portion of  ls_name's property list beginning with the 
+property under the indicator g_ind.
+If there is no g_ind indicator in ls_name's plist, nil is returned.
+.Se
+the value under indicator g_ind and g_ind itself is removed from 
+the property list of ls_name.
+.No
+ls_name may be a disembodied property list, see \fIget\fP.
+
+.Eb
+\-> \fI(putprop 'xlate 'a 'alpha)\fP
+a
+\-> \fI(putprop 'xlate 'b 'beta)\fP
+b
+\-> \fI(plist 'xlate)\fP
+(alpha a beta b)
+\-> \fI(get 'xlate 'alpha)\fP
+a
+; use of a disembodied property list:
+\-> \fI(get '(nil fateman rjf sklower kls foderaro jkf) 'sklower)\fP
+kls
+.Ee
+.sh 3 tconc\ structure
+.pp
+A tconc structure is a special type of list designed to make it
+easy to add objects to the end.
+It consists of a list cell whose 
+.i car
+points to a 
+list of the elements added with 
+.i tconc
+or 
+.i lconc
+and whose
+.i cdr
+points to the last list cell of the list pointed to by the 
+.i car.
+.Lf tconc "'l_ptr 'g_x"
+.Wh
+l_ptr is a tconc structure.
+.Re
+l_ptr with g_x added to the end.
+.Lf lconc "'l_ptr 'l_x"
+.Wh
+l_ptr is a tconc structure.
+.Re
+l_ptr with the list l_x spliced in at the end.
+.Eb
+; A \fItconc\fP structure can be initialized in two  ways.  
+; nil can be given to \fItconc\fP in which case \fItconc\fP will generate 
+; a \fItconc\fP structure.
+
+\->\fI(setq foo (tconc nil 1))\fP
+((1) 1)
+
+; Since \fItconc\fP destructively adds to 
+; the list, you can now add to foo without using \fIsetq\fP again.
+
+\->\fI(tconc foo 2)\fP
+((1 2) 2)
+\->\fIfoo\fP
+((1 2) 2)
+
+; Another way to create a null  \fItconc\fP structure
+; is to use \fI(ncons\ nil)\fP.
+
+\->\fI(setq foo (ncons nil))\fP
+(nil)
+\->\fI(tconc foo 1)\fP
+((1) 1)
+
+; now see what \fIlconc\fP can do
+\-> \fI(lconc foo nil)\fP
+((1) 1)                        ; no change
+\-> \fI(lconc foo '(2 3 4))\fP
+((1 2 3 4) 4)
+.Ee
+.sh 3 fclosures
+.pp
+An fclosure is a functional object which admits some data
+manipulations.  They are discussed in \(sc8.4.
+Internally, they are constructed from vectors.
+.Lf fclosure "'l_vars 'g_funobj"
+.Wh
+l_vars is a list of variables, g_funobj is any object
+that can be funcalled (including, fclosures).
+.Re
+A vector which is the fclosure.
+.Lf fclosure-alist "'v_fclosure"
+.Re
+An association list representing the variables in the fclosure.
+This is a snapshot of the current state of the fclosure.
+If the bindings in the fclosure are changed, any previously
+calculated results of
+.i fclosure-alist
+will not change.
+.Lf fclosure-function "'v_fclosure"
+.Re
+the functional object part of the fclosure.
+.Lf fclosurep "'v_fclosure"
+.Re
+t iff the argument is an fclosure.
+.Lf symeval-in-fclosure "'v_fclosure 's_symbol"
+.Re
+the current binding of a particular symbol in an fclosure.
+.Lf set-in-fclosure "'v_fclosure 's_symbol 'g_newvalue"
+.Re
+g_newvalue.
+.Se
+The variable s_symbol is bound in the fclosure to g_newvalue.
+.sh 2 Random\ functions
+.pp
+The following functions don't fall into any of the classifications above.
+.Lf bcdad "'s_funcname"
+.Re
+a fixnum which is the address in memory where the function 
+s_funcname begins.
+If s_funcname is not a machine coded function (binary) then 
+.i bcdad 
+returns nil.
+.Lf copy "'g_arg"
+.Re
+A structure 
+.i equal
+to g_arg but with new list cells.
+.Lf copyint* "'x_arg"
+.Re
+a fixnum with the same value as x_arg but in a freshly allocated cell.
+.Lf cpy1 "'xvt_arg"
+.Re
+a new cell of the same type as xvt_arg with the same value as xvt_arg.
+.Lf getaddress "'s_entry1 's_binder1 'st_discipline1 [... ... ...]"
+.Re
+the binary object which s_binder1's  function field is set to.
+.No
+This looks in the running lisp's symbol table for a symbol with the same
+name as s_entry\fIi\fP.
+It then creates a binary object
+whose entry field points to s_entry\fIi\fP 
+and whose discipline is st_discipline\fIi\fP.
+This binary object is stored in the function field of s_binder\fIi\fP.
+If st_discipline\fIi\fP is nil, then "subroutine" is used by default.
+This is especially useful for 
+.i cfasl
+users.
+.Lf macroexpand "'g_form"
+.Re
+g_form after all macros in it are
+expanded.
+.No
+This function will only macroexpand 
+expressions which could be evaluated
+and it does not know about the special nlambdas such as 
+.i cond
+and
+.i do ,
+thus it misses many macro expansions.
+.Lf ptr "'g_arg"
+.Re
+a value cell initialized to point to g_arg.
+.Lf quote "g_arg"
+.Re
+g_arg.
+.No
+the reader allows you to abbreviate (quote foo) as 'foo.
+.Lf kwote "'g_arg"
+.Re
+ \fI(list (quote quote) g_arg)\fP.
+.Lf replace "'g_arg1 'g_arg2"
+.Wh
+g_arg1 and g_arg2 must be the same type of lispval and not symbols or hunks.
+.Re
+g_arg2.
+.Se
+The effect of
+.i replace 
+is dependent on the type of the g_arg\fIi\fP although one will notice 
+a similarity in the effects.
+To understand what 
+.i replace
+does to fixnum and flonum arguments,
+you must first understand that 
+such numbers are `boxed' in 
+.Fr .
+What this means is that if the symbol x has a value 32412, then in
+memory the value element of x's symbol structure contains the address of
+another word of memory (called a box) with 32412 in it.
+.br
+.sp
+Thus, there are two ways of changing the value of x:
+the first is to change
+the value element of x's symbol structure to point to a word of memory
+with a different value.
+The second way is to change the value in the box which x points to.
+The former method is used almost all of the time, the latter is
+used very rarely and has the potential to cause great confusion.
+The function
+.i replace
+allows you to do the latter, i.e., to actually change the value in
+the box.
+.br
+.sp
+You should watch out for these situations.
+If you do \fI(setq\ y\ x)\fP,
+then both x and y will point to the same box.
+If you now \fI(replace\ x\ 12345)\fP,
+then y will also have the value 12345.
+And, in fact, there may be many other pointers to that box.
+.br
+.sp
+Another problem with replacing fixnums
+is that some boxes are read-only.
+The fixnums between -1024 and 1023 are stored in a read-only area
+and attempts to replace them will result in an "Illegal memory reference"
+error (see the description of 
+.i copyint*
+for a way around this problem).
+.br
+.sp
+For the other valid types, the effect of 
+.i replace 
+is easy to understand.
+The fields of g_val1's structure are made eq to the corresponding fields of
+g_val2's structure.
+For example, if x  and  y have lists as values then the effect of
+\fI(replace\ x\ y)\fP is the same as 
+\fI(rplaca\ x\ (car\ y))\fP and \fI(rplacd\ x\ (cdr\ y))\fP.
+.Lf scons "'x_arg 'bs_rest"
+.Wh
+bs_rest is a bignum or nil.
+.Re
+a bignum whose first bigit is x_arg 
+and whose higher order bigits are bs_rest.
+.Lf setf "g_refexpr 'g_value"
+.No
+.i setf
+is a generalization of setq.  Information may be stored by
+binding variables, replacing entries of arrays, and vectors,
+or being put on property lists, among others.
+Setf will allow the user to store data into some location,
+by mentioning the operation used to refer to the location.
+Thus, the first argument may be partially evaluated, but only
+to the extent needed to calculate a reference.
+.i setf
+returns g_value.
+.Eb
+  (setf x 3)        =  (setq x 3)
+  (setf (car x) 3)  = (rplaca x 3)
+  (setf (get foo 'bar) 3) = (putprop foo 3 'bar)
+  (setf (vref vector index) value) = (vset vector index value)
+.Ee
+.Lf sort "'l_data 'u_comparefn"
+.Re
+a list of the elements of l_data ordered by the comparison
+function u_comparefn
+.Se
+the list l_data is modified rather than allocate new storage.
+.No
+\fI(comparefn 'g_x 'g_y)\fP should return something
+non-nil if g-x can precede g_y in sorted order; nil if g_y must precede
+g_x.  
+If u_comparefn is nil, 
+alphabetical order will be used.
+.Lf sortcar "'l_list 'u_comparefn"
+.Re
+a list of the elements of l_list with the 
+.i car 's
+ordered by the sort function u_comparefn.
+.Se
+the list l_list is modified rather than allocating new storage.
+.No
+Like \fIsort\fP, 
+if u_comparefn is nil, 
+alphabetical order will be used.
diff --git a/usr/lisp/ch4.n b/usr/lisp/ch4.n
new file mode 100644 (file)
index 0000000..9e91830
--- /dev/null
@@ -0,0 +1,1028 @@
+." $Header: ch4.n 1.4 83/07/27 15:11:44 layer Exp $
+.pp
+.Lc Special\ Functions 4
+.Lf and "[g_arg1 ...]"
+.Re
+the value of the last argument if all arguments evaluate
+to a non-nil value, otherwise 
+.i and 
+returns nil.
+It returns t if there are no arguments.
+.No
+the arguments are evaluated left to right and evaluation will cease
+with the first nil encountered
+.Lf apply "'u_func 'l_args"
+.Re
+the result of applying function u_func to the arguments in the list l_args.
+.No
+If u_func is a lambda, then the \fI(length\ l_args)\fP should equal the
+number of formal parameters for the u_func.
+If u_func is a nlambda or macro, then l_args is bound to the single
+formal parameter.
+.Eb
+; \fIadd1\fP is a lambda of 1 argument
+\-> \fI(apply 'add1 '(3))\fP
+4
+
+; we will define \fIplus1\fP as a macro which will be equivalent to \fIadd1\fP
+\-> \fI(def plus1 (macro (arg) (list 'add1 (cadr arg))))\fP
+plus1
+\-> \fI(plus1 3)\fP
+4
+
+; now if we \fIapply\fP a macro we obtain the form it changes to.
+\-> \fI(apply 'plus1 '(plus1 3))\fP
+(add1 3)
+
+; if we \fIfuncall\fP a macro however, the result of the macro is \fIeval\fPed
+; before it is returned.
+\-> \fI(funcall 'plus1 '(plus1 3))\fP
+4
+
+; for this particular macro, the \fIcar\fP of the \fIarg\fP is not checked
+; so that this too will work
+\-> \fI(apply 'plus1 '(foo 3))\fP
+(add1 3)
+
+.Ee
+.Lf arg "['x_numb]"
+.Re 
+if x_numb is specified then the x_numb'\fIth\fP argument to 
+the enclosing lexpr
+If x_numb is not specified then this returns the number of arguments 
+to the enclosing lexpr.
+.No
+it is an error to the interpreter if x_numb is given and out of range.
+.Lf break "[g_message ['g_pred]]"
+.Wh
+if g_message is not given it is assumed to be the null string, and
+if g_pred is not given it is assumed to be t.
+.Re
+the value of \fI(*break 'g_pred 'g_message)\fP
+.Lf *break "'g_pred 'g_message"
+.Re
+nil immediately if g_pred is nil, else
+the value of the next (return 'value) expression typed in at top level.
+.Se
+If the predicate, g_pred, evaluates to non-null,
+the lisp system stops and prints out `Break '
+followed by g_message. 
+It then enters a break loop
+which allows one to interactively debug a program.
+To continue execution from a break you can use the
+.i return 
+function. 
+to return to top level or another break level, you can use
+.i retbrk 
+or 
+.i reset .
+.Lf caseq "'g_key-form l_clause1 ..."
+.Wh 
+l_clause\fIi\fP is a list of the form
+(g_comparator ['g_form\fIi\fP ...]).
+The comparators may be symbols, small fixnums, a list of small fixnums or
+symbols.
+.No
+The way caseq works is that it evaluates g_key-form,
+yielding a value we will call the selector.
+Each clause is examined until the selector is found
+consistent with the comparator.
+For a symbol, or a fixnum, this means the two must be \fIeq\fP.
+For a list, this means that the selector must be \fIeq\fP to
+some element of the list.
+.br
+.sp
+The symbol \fBt\fP has special semantics:
+it matches anything, and consequently, should be the last comparator.
+Then, having chosen a clause, \fIcaseq\fP evaluates each form
+within that clause and
+.Re
+the value of the last form.  If no comparators are matched,
+\fIcaseq\fP returns nil.
+.Eb
+Here are two ways of defining the same function:
+\->\fI(defun fate (personna)
+       (caseq personna
+         (cow '(jumped over the moon))
+         (cat '(played nero))
+         ((dish spoon) '(ran away together))
+         (t '(lived happily ever after))))\fP
+fate
+\->\fI(defun fate (personna)
+       (cond
+               ((eq personna 'cow) '(jumped over the moon))
+               ((eq personna 'cat) '(played nero))
+               ((memq personna '(dish spoon)) '(ran away together))
+               (t '(lived happily ever after))))\fP
+fate
+.Ee
+.Lf catch "g_exp [ls_tag]"
+.Wh
+if ls_tag is not given, it is assumed to be nil.
+.Re
+the result of \fI(*catch 'ls_tag g_exp)\fP
+.No
+catch is defined as a macro.
+.Lf *catch "'ls_tag g_exp"
+.Wh
+ls_tag is either a symbol or a list of symbols.
+.Re
+the result of evaluating g_exp or the value thrown during the evaluation
+of g_exp.
+.Se
+this first sets up a `catch frame' on the lisp runtime stack.
+Then it begins to evaluate g_exp.
+If g_exp evaluates normally, its value is returned.
+If, however, a value is thrown during the evaluation of g_exp then
+this *catch will return with that value if one of these cases
+is true:
+.nr $p 0
+.np
+the tag thrown to is ls_tag 
+.np
+ls_tag is a list and the tag thrown to is a member of this list
+.np
+ls_tag is nil.
+.No
+Errors are implemented as a special kind of throw.
+A catch with no tag will not catch an error but a catch whose tag is
+the error type will catch that type of error.
+See Chapter 10 for more information.
+.Lf comment "[g_arg ...]"
+.Re
+the symbol comment.
+.No
+This does absolutely nothing.
+.Lf cond "[l_clause1 ...]"
+.Re
+the last value evaluated in the first clause satisfied.
+If no clauses are satisfied then nil is returned.
+.No
+This is the basic conditional `statement' in lisp.
+The clauses are processed from left to right.
+The first element of a clause is evaluated.
+If it evaluated to a non-null value then that clause is satisfied and
+all following elements of that clause are evaluated.
+The last value computed is returned as the value of the cond.
+If there is just one element in the clause then its value is returned.
+If the first element of a clause evaluates to nil, then the other
+elements of that clause are not evaluated and the system moves to
+the next clause.
+.Lf cvttointlisp
+.Se
+The reader is modified to conform with the Interlisp syntax.
+The character % is made the escape character and special meanings for
+comma, backquote and backslash are removed. 
+Also the reader is told to convert upper case to lower case. 
+.Lf cvttofranzlisp
+.Se
+The reader is modified to conform with franz's default syntax.
+One would run this function after having run cvttomaclisp, only.
+Backslash is made the escape character, and super-brackets are
+reinstated.  The reader is reminded to distinguish between upper and
+lower case.
+.Lf cvttomaclisp
+.Se
+The reader is modified to conform with Maclisp syntax.
+The character / is made the escape character and the special meanings
+for backslash, left and right bracket are removed.
+The reader is made case-insensitive.
+.Lf cvttoucilisp
+.Se
+The reader is modified to conform with UCI Lisp syntax.
+The character / is made the escape character, tilde is made the comment
+character, exclamation point takes on the unquote function normally
+held by comma, and backslash, comma, semicolon become normal 
+characters.
+Here too, the reader is made case-insensitive.
+.Lf debug "s_msg"
+.Se
+Enter the Fixit package described in Chapter 15.
+This package allows you to examine the evaluation stack in detail.
+To  leave the Fixit package type 'ok'.
+.Lf debugging "'g_arg"
+.Se
+If g_arg is non-null,
+Franz unlinks the transfer tables, does a \fI(*rset\ t)\fP to turn on
+evaluation monitoring and sets the all-error catcher (ER%all) to be
+\fIdebug-err-handler\fP.
+If g_arg is nil,
+all of the above changes are undone.
+.Lf declare "[g_arg ...]"
+.Re
+nil
+.No
+this is a no-op to the evaluator.
+It has special meaning to the compiler (see Chapter 12).
+.Lf def "s_name (s_type l_argl g_exp1 ...)"
+.Wh
+s_type is one of lambda, nlambda, macro or lexpr.
+.Re
+s_name
+.Se
+This defines the function s_name to the lisp system.
+If s_type is nlambda or macro then the argument list l_argl must contain
+exactly one non-nil symbol.
+.Lf defmacro "s_name l_arg g_exp1 ..."
+.Lx defcmacro "s_name l_arg g_exp1 ..."
+.Re
+s_name
+.Se
+This defines the macro s_name.  
+\fIdefmacro\fP makes it easy to write macros since it makes
+the syntax just like \fIdefun\fP.
+Further information on \fIdefmacro\fP is in \(sc8.3.2.
+\fIdefcmacro\fP defines compiler-only macros, or cmacros.  
+A cmacro is stored on the property list of a
+symbol under the indicator \fBcmacro\fP.
+Thus a function can
+have a normal definition and a cmacro definition.
+For an example of the use of cmacros, see the definitions
+of nthcdr and nth in /usr/lib/lisp/common2.l
+.Lf defun "s_name [s_mtype] ls_argl g_exp1 ... "
+.Wh
+s_mtype is one of fexpr, expr, args or macro.
+.Re
+s_name
+.Se
+This defines the function s_name.
+.No
+this exists for Maclisp compatibility, it is just a macro which
+changes the defun form to the def form.
+An s_mtype of fexpr is converted to nlambda
+and of expr to lambda. Macro remains the same.
+If ls_arg1 is a non-nil symbol, then the type is assumed to be lexpr and
+ls_arg1 is the symbol which is bound to the number of args when the
+function is entered.
+.br
+For compatability with the Lisp Machine lisp, there are three types of
+optional parameters that can occur in ls_argl:  \fI&optional\fP declares that
+the following symbols are optional, and may or may not appear in the
+argument list to the function, \fI&rest symbol\fP
+declares that all forms in the
+function call that are not accounted for by previous lambda bindings
+are to be assigned to \fIsymbol\fP, and \fI&aux form1 ... formn\fP
+declares that the \fIformi\fP are either symbols, in which case they
+are lambda bound to \fBnil\fP, or lists, in which case the first element
+of the list is lambda bound to the second, evaluated element.
+.Eb
+; \fIdef\fP and \fIdefun\fP here are used to define identical functions
+; you can decide for yourself which is easier to use.
+\-> \fI(def append1 (lambda (lis extra) (append lis (list extra))))\fP
+append1
+
+\-> \fI(defun append1 (lis extra) (append lis (list extra)))\fP
+append1
+
+; Using the & forms...
+\-> \fI(defu\kCn test (a b &optional c &aux (retval 0) &rest z)
+        \h'|\nCu'\kB(if c them (msg \kA"Optional arg present" N
+                        \h'|\nAu'"c is " c N))
+        \h'|\nBu'(msg \kA"rest is " z N
+             \h'|\nAu'"retval is " retval N))\fP
+test
+\-> \fI(test 1 2 3 4)\fP
+Optional arg present
+c is 3
+rest is (4)
+retval is 0
+.Ee
+.Lf defvar "s_variable ['g_init]"
+.Re
+s_variable.
+.No
+This form is put at the top level in files, like \fIdefun\fB.
+.Se
+This declares s_variable to be special. If g_init is present,
+and s_variable is unbound when the file is read in, s_variable
+will be set to the value of g_init.
+An advantage of `(defvar foo)' over `(declare (special foo))' is that if
+a file containing defvars is loaded (or fasl'ed) in during compilation,
+the variables mentioned in the defvar's will be declared special.  The only
+way to have that effect with `(declare (special foo))' is to \fIinclude\fP
+the file.  
+.Lf do "l_vrbs l_test g_exp1 ..."
+.Re
+the last form in the cdr of l_test evaluated, or a value explicitly given by
+a return evaluated within the do body.
+.No
+This is the basic iteration form for
+.Fr .
+l_vrbs is a list of zero or more var-init-repeat forms.
+A var-init-repeat form looks like:
+.br
+.tl ''(s_name [g_init [g_repeat]])''
+There are three cases depending on what is present in the form.
+If just s_name is present, this means that when the do is entered,
+s_name is lambda-bound to nil and is never modified by the system 
+(though the program is certainly free to modify its value).
+If the form is (s_name\ 'g_init) then the only difference is that
+s_name is lambda-bound to the value of g_init instead of nil.
+If g_repeat is also present then s_name is lambda-bound to g_init
+when the loop is entered and after each pass through the do body
+s_name is  bound to the value of g_repeat.
+.br
+l_test is either nil or has the form of a cond clause.
+If it is nil then the do body will be evaluated only once and the
+do will return nil.
+Otherwise, before the do body is evaluated the car of l_test is 
+evaluated and if the result is non-null, this signals an end to
+the looping.
+Then the rest of the forms in l_test are evaluated
+and the value of the last one is returned as the value of the do.
+If the cdr of l_test is nil, then nil is returned -- thus this is not
+exactly like a cond clause.
+.br
+g_exp1 and those forms which follow constitute the do body.
+A do body is like a prog body and thus may have labels and one may
+use the functions go and return.
+.br
+The sequence of evaluations is this:
+.nr $p 0
+.np
+the init forms are evaluated left to right and  stored in temporary
+locations.
+.np
+Simultaneously all do variables are lambda bound to the value of
+their init forms or nil.
+.np
+If l_test is non-null, then the car is evaluated and if it is non-null,
+the rest of the forms in l_test are evaluated and the last value is 
+returned as the value
+of the do.
+.np
+The forms in the do body are evaluated left to right.
+.np
+If l_test is nil the do function returns with the value nil.
+.np
+The repeat forms are evaluated and saved in temporary locations.
+.np
+The variables with repeat forms are simultaneously
+bound to the values of those forms.
+.np
+Go to step 3.
+.No
+there is an alternate form of do which can be used when there is
+only one do variable.
+It is described next.
+.Eb
+; this is  a simple function which numbers the elements of a list.
+; It uses a \fIdo\fP function with two local variables.
+\-> \fI(defun printem (lis)
+            (do ((xx lis (cdr xx))
+                 (i 1 (1+ i)))
+                ((null xx) (patom "all done") (terpr))
+                (print i)
+                (patom ": ")
+                (print (car xx))
+                (terpr)))\fP
+printem
+\-> \fI(printem '(a b c d))\fP
+1: a
+2: b
+3: c
+4: d
+all done
+nil
+\-> 
+.Ee
+.Lf do "s_name g_init g_repeat g_test g_exp1 ..."
+.nr $p 0
+.No
+this is another, less general,  form of do.
+It is evaluated by:
+.np
+evaluating g_init
+.np
+lambda binding s_name to value of g_init
+.np
+g_test is evaluated and if it is not nil the do function returns with nil.
+.np
+the do body is evaluated beginning at g_exp1.
+.np
+the repeat form is evaluated and stored in s_name.
+.np
+go to step 3.
+.Re
+nil
+.Lf environment "[l_when1 l_what1 l_when2 l_what2 ...]"
+.Lx environment-maclisp "[l_when1 l_what1 l_when2 l_what2 ...]"
+.Lx environment-lmlisp "[l_when1 l_what1 l_when2 l_what2 ...]"
+.Wh
+the when's are a subset of (eval compile load), and the symbols have the
+same meaning as they do in 'eval-when'.
+.br
+.sp
+The what's may be 
+.br
+       (files file1 file2 ... fileN),
+.br
+which insure that the named files are loaded.
+To see if file\fIi\fP is loaded,
+it looks for a 'version' property under
+file\fIi\fP's property list.  Thus to prevent multiple loading,
+you should put
+.br
+       (putprop 'myfile t 'version),
+.br
+at the end of myfile.l.
+.br
+.sp
+Another acceptible form for a what is
+.br
+(syntax type)
+.br
+Where type is either maclisp, intlisp, ucilisp, franzlisp.
+This sets the syntax correctly.
+.br
+.sp
+\fIenvironment-maclisp\fP sets the environment to that which
+`liszt -m' would generate.
+\fIenvironment-lmlisp\fP  sets up the lisp machine environment. This is like
+maclisp but it has additional macros.
+For these specialized environments, only the \fBfiles\fP clauses are useful.
+.Eg
+       (environment-maclisp (compile eval) (files foo bar))
+.Lf err "['s_value [nil]]"
+.Re
+nothing (it never returns).
+.Se
+This causes an error and if this error is caught by an 
+.i errset
+then that 
+.i errset
+will return s_value instead of nil.
+If the second arg is given, then it must be nil (\s-2MAC\s0lisp 
+compatibility).
+.Lf error "['s_message1 ['s_message2]]"
+.Re
+nothing (it never returns).
+.Se
+s_message1 and s_message2 are \fIpatom\fPed if they are given and
+then \fIerr\fP is called (with no arguments), which causes an error.
+.Lf errset "g_expr [s_flag]"
+.Re
+a list of one element, which is the value resulting from evaluating g_expr.
+If an error occurs during the evaluation of g_expr, then the locus of control
+will return to the 
+.i errset
+which will then return nil (unless the error was caused by a call to
+.i err,
+with a non-null argument).
+.Se
+S_flag is evaluated before g_expr is evaluated. 
+If s_flag is not given, then it is assumed to be t.
+If an error occurs during the evaluation of g_expr, and s_flag evaluated to 
+a non-null value, then the error message associated with the
+error is printed before control returns to the errset.
+.Lf eval "'g_val ['x_bind-pointer]"
+.Re
+the result of evaluating g_val.
+.No
+The evaluator evaluates g_val in this way:
+.br
+If g_val is a symbol, then the evaluator returns its value.
+If g_val had never been assigned a value, then this causes 
+an `Unbound Variable' error.
+If x_bind-pointer is given, then the variable is evaluated with
+respect to that pointer (see \fIevalframe\fP for details on bind-pointers).
+.br
+.sp
+If g_val is of type value, then its value is returned.
+If g_val is of any other type than list, g_val is returned.
+.br
+.sp
+If g_val is a list object then g_val is either a function call or
+array reference.
+Let g_car be the first element of g_val.
+We continually evaluate g_car until we end up with a symbol with
+a non-null function binding
+or a non-symbol.
+Call what we end up with: g_func.
+.br
+.sp
+G_func must be one of three types: list, binary or array.
+If it is a list then the first element of the list, which 
+we shall call g_functype, must be either
+lambda, nlambda, macro or lexpr.
+If g_func is a binary, then its discipline, which we shall call
+g_functype, is either lambda, nlambda, macro or a string.
+If g_func is an array then this form is evaluated specially, see
+Chapter 9 on arrays.
+If g_func is a list or binary, then g_functype will determine how
+the arguments to this function, the cdr of g_val, are processed.
+If g_functype is a string, then this is a foreign function call (see \(sc8.5
+for more details).
+.br
+.sp
+If g_functype is lambda or lexpr, the arguments are evaluated
+(by calling 
+.i eval
+recursively) and stacked.
+If g_functype is nlambda then the argument list is stacked.
+If g_functype is macro then the entire form, g_val is stacked.
+.br
+.sp
+Next, the formal variables are lambda bound.
+The formal variables are the cadr of g_func.  If g_functype is
+nlambda, lexpr or macro, there should only be one formal variable.
+The values on the stack are lambda bound to the formal variables
+except in the case of a lexpr, where the number of actual arguments
+is bound to the formal variable.
+.br
+.sp
+After the binding is done, the function is invoked, either by
+jumping to the entry point in the case of a binary or 
+by evaluating the list of forms beginning at cddr g_func.
+The result of this function invocation is returned as the value 
+of the call to eval.
+.Lf evalframe "'x_pdlpointer"
+.Re
+an evalframe descriptor for the evaluation frame just before x_pdlpointer.
+If x_pdlpointer is nil, it returns the evaluation frame of the frame just
+before the current call to \fIevalframe\fP.
+.No
+An evalframe descriptor describes a call to \fIeval\fP, \fIapply\fP
+or \fIfuncall\fP.
+The form of the descriptor is 
+.br
+\fI(type pdl-pointer expression bind-pointer np-index lbot-index)\fP
+.br
+where type is `eval' if this describes a call to \fIeval\fP or `apply'
+if this is a call to \fIapply\fP or \fIfuncall\fP.
+pdl-pointer is a number which  describes
+this context. 
+It can be passed to
+.i evalframe
+to obtain the next descriptor and
+can be passed to 
+.i freturn
+to cause a return from this context.
+bind-pointer is the size of variable  binding stack when this
+evaluation began. 
+The bind-pointer can be given as a second argument
+to \fIeval\fP to order to evaluate variables in the same context as
+this  evaluation. 
+If type is `eval' then expression
+will have the form \fI(function-name\ arg1\ ...)\fP.
+If type is `apply' then expression will have the form
+\fI(function-name\ (arg1\ ...))\fP.
+np-index and lbot-index are pointers into the
+argument stack (also known as the \fInamestack\fP array) at the time of call.
+lbot-index points to the first argument, np-index points one beyond
+the last argument.
+.br
+In order for there to be enough information
+for \fIevalframe\fP to return, you must call \fI(*rset\ t)\fP.
+.Ex
+\fI(progn (evalframe nil))\fP
+.br
+returns \fI(eval 2147478600 (progn (evalframe nil)) 1 8 7)\fP
+.Lf evalhook "'g_form 'su_evalfunc ['su_funcallfunc]"
+.Re 
+the result of evaluating g_form after lambda binding `evalhook' to
+su_evalfunc and, if it is given, lambda binding `funcallhook' to 
+su_funcallhook.
+.No
+As explained in \(sc14.4, the function
+.i eval
+may pass the job of evaluating a form to a user `hook' function when 
+various switches are set.
+The  hook function normally prints the form to be evaluated on the
+terminal and then evaluates it by calling 
+.i evalhook .
+.i Evalhook
+does the lambda binding mentioned above and then calls 
+.i eval 
+to evaluate the form after setting an internal switch to tell 
+.i eval
+not to call the user's hook function just this one time.
+This allows the evaluation process to advance one step and yet
+insure that further calls to 
+.i eval
+will cause traps to the hook function (if su_evalfunc is non-null).
+.br
+In order for \fIevalhook\fP to work, \fI(*rset\ t)\fP and 
+\fI(sstatus\ evalhook\ t)\fP must have been done previously.
+.Lf exec "s_arg1 ..."
+.Re
+the result of forking and executing the command named by concatenating
+the s_arg\fIi\fP together with spaces in between.
+.Lf exece "'s_fname ['l_args ['l_envir]]"
+.Re
+the error code from the system if it was unable to 
+execute the command s_fname with arguments
+l_args and with the environment set up as specified in l_envir.
+If this function is successful, it will not return, instead the lisp
+system will be overlaid by the new command.
+.Lf freturn "'x_pdl-pointer 'g_retval"
+.Re
+g_retval from the context given by x_pdl-pointer.
+.No
+A pdl-pointer denotes a certain expression currently being evaluated.  
+The pdl-pointer for a given expression can be obtained from
+.i evalframe .
+.Lf frexp "'f_arg"
+.Re
+a list cell \fI(exponent . mantissa)\fP which represents the 
+given flonum
+.No
+The exponent will be a fixnum, the mantissa a 56 bit bignum.
+If you think of the the binary point occurring right after the
+high order bit of mantissa, then
+f_arg\ =\ 2\*[exponent\*]\ *\ mantissa.
+.Lf funcall "'u_func ['g_arg1 ...]"
+.Re
+the value of applying function u_func to the arguments g_arg\fIi\fP
+and then evaluating that result if u_func is a macro.
+.No
+If u_func is a macro or nlambda then there should be only one g_arg.
+\fIfuncall\fP is the function which the evaluator uses to evaluate
+lists.
+If \fIfoo\fP is a lambda or lexpr or array, 
+then \fI(funcall\ 'foo\ 'a\ 'b\ 'c)\fP
+is equivalent to \fI(foo\ 'a\ 'b\ 'c)\fP.
+If \fIfoo\fP is a nlambda
+then \fI(funcall\ 'foo\ '(a\ b\ c))\fP is equivalent to
+\fI(foo a b c)\fP.
+Finally, if 
+.i foo
+is a macro then
+.i (funcall\ 'foo\ '(foo\ a\ b\ c))
+is equivalent to
+.i (foo\ a\ b\ c) .
+.Lf funcallhook "'l_form 'su_funcallfunc ['su_evalfunc]"
+.Re 
+the result of \fIfuncall\fPing 
+the \fI(car\ l_form)\fP
+on the already evaluated
+arguments in the \fI(cdr\ l_form)\fP 
+after lambda binding `funcallhook' to
+su_funcallfunc and, if it is given, lambda binding `evalhook' to 
+su_evalhook.
+.No
+This function is designed to continue the evaluation process 
+with as little work as possible after a funcallhook trap has occurred. 
+It is for this reason that the form of l_form is unorthodox: its 
+.i car
+is the name of the function to call and its 
+.i cdr
+are a list of arguments to stack (without evaluating again)
+before calling the given function.
+After stacking the arguments 
+but
+before calling
+.i funcall
+an internal switch is set to prevent \fIfuncall\fP
+from passing the job of funcalling to su_funcallfunc.
+If \fIfuncall\fP is called recursively in funcalling l_form and
+if su_funcallfunc is non-null, then 
+the arguments to 
+.i funcall
+will actually be given to su_funcallfunc (a lexpr) 
+to be funcalled.
+.br
+In order for \fIevalhook\fP to work, \fI(*rset\ t)\fP and 
+\fI(sstatus\ evalhook\ t)\fP must have been done previously.
+A more detailed description of 
+.i evalhook
+and 
+.i funcallhook
+is given in Chapter 14.
+.Lf function "u_func"
+.Re
+the function binding of u_func if it is an symbol with a function binding
+otherwise u_func is returned.
+.Lf getdisc "'y_func"
+.Re
+the discipline of the machine coded function (either lambda, nlambda
+or macro).
+.Lf go "g_labexp"
+.Wh
+g_labexp is either a symbol or an expression.
+.Se
+If g_labexp is an expression, that expression is evaluated and 
+should
+result in a symbol.
+The locus of control moves to just following the symbol g_labexp in the
+current prog or do body.
+.No
+this is only valid in the context of a prog or do body.
+The interpreter and compiler will allow non-local 
+.i go 's 
+although the compiler won't allow a \fIgo\fP to leave a function body.
+The compiler will not allow g_labexp to be an expression.
+.Lf if "'g_a 'g_b"
+.Lx if "'g_a 'g_b 'g_c ..."
+.Lx if "'g_a \fBthen\fP  'g_b [...] [\fBelseif\fP 'g_c \fBthen\fP 'g_d ...] [\fBelse\fP 'g_e [...]"
+.Lx if "'g_a \fBthen\fP  'g_b [...] [\fBelseif\fP 'g_c \fBthenret\fP] [\fBelse\fP 'g_d [...]"
+.No
+The various forms of \fIif\fP are intended to be a more readable
+conditional statement, to be used in place of \fIcond\fP.  There
+are two varieties of \fIif\fP, with keywords, and without.  The
+keyword-less variety is inherited from common Maclisp usage.
+A keyword-less, two argument \fIif\fP is equivalent to a one-clause
+\fIcond\fP, i.e. (\fIcond\fP (a b)).   Any other keyword-less \fIif\fP
+must have at least three arguments.  The first two arguments are the
+first clause of the equivalent \fIcond\fP, and all remaining arguments
+are shoved into a second clause beginning with \fBt\fP.  Thus, the
+second form of \fIif\fP is equivalent to
+.br
+       (\fIcond\fP (a b) (t c ...)).
+.br
+.sp
+The keyword variety has the following grouping of arguments:
+a predicate, a then-clause, and optional
+else-clause.  The predicate is evaluated, and if the result is
+non-nil, the then-clause will be performed, in the sense
+described below.  Otherwise, (i.e. the result of the predicate
+evaluation was precisely nil), the else-clause will be performed.
+.br
+.sp
+Then-clauses will either consist entirely
+of the single keyword \fBthenret\fP, or will start with the keyword
+\fBthen\fP, and be followed by at least one general expression.
+(These general expressions must not be one of the keywords.)
+To actuate a \fBthenret\fP means to cease further evaluation
+of the \fIif\fP, and to return the value of the predicate just calculated.
+The performance of the longer clause means to evaluate each general expression
+in turn, and then return the last value calculated.
+.br
+.sp
+The else-clause may begin with the keyword \fBelse\fP and be followed
+by at least one general expression.
+The rendition of this clause is just like that of a then-clause.
+An else-clause
+may begin alternatively with the keyword \fBelseif\fP, and be followed
+(recursively) by a predicate, then-clause, and optional else-clause.
+Evaluation of this clause, is just evaluation of an \fIif\fP-form, with
+the same predicate, then- and else-clauses.
+.Lf I-throw-err "'l_token"
+.Wh
+l_token is the \fIcdr\fP of the value returned from a \fI*catch\fP with
+the tag ER%unwind-protect.
+.Re
+nothing (never returns in the current context)
+.Se
+The error or throw denoted by l_token is continued.
+.No
+This function is used to implement \fIunwind-protect\fP which allows the
+processing of a transfer of control though a certain context to be
+interrupted, a user function to be executed and than the transfer of
+control to continue.
+The form of l_token is either
+.br
+\fI(t tag value)\fP for a throw or
+.br
+\fI(nil type message valret contuab uniqueid [arg ...])\fP for an error.
+.br
+This function is not to be used for implementing throws or
+errors and is only documented here for completeness.
+.Lf let "l_args g_exp1 ... g_exprn"
+.Re
+the result of evaluating g_exprn within the bindings given by l_args.
+.No
+l_args is either nil (in which case 
+.i let
+is just like
+.i progn )
+or it is a list of binding objects.
+A binding object is a list \fI(symbol\ expression)\fP.
+When a 
+.i let 
+is entered all of the expressions are evaluated and then simultaneously
+lambda bound to the corresponding symbols.
+In effect, a 
+.i let
+expression is just like a lambda expression except the symbols and
+their initial values are next to each other which makes the expression
+easier to understand.
+There are some added features to the 
+.i let 
+expression:
+A binding object can just be a symbol, in which case the expression
+corresponding to that symbol is `nil'.
+If a binding object is a list and the first element of that list is
+another list, then that list is assumed to be a binding template
+and 
+.i let
+will do a 
+.i desetq
+on it.
+.Lf let* "l_args g_exp1 ... g_expn"
+.Re
+the result of evaluating g_exprn within the bindings given by l_args.
+.No
+This is identical to 
+.i let
+except the expressions in the binding list l_args are evaluated
+and bound sequentially instead of in parallel.
+.Lf lexpr-funcall "'g_function ['g_arg1 ...] 'l_argn"
+.No
+This is a cross between funcall and apply.
+The last argument, must be a list (possibly empty).
+The element of list arg are stack and then the function is
+funcalled.
+.Ex
+(lexpr-funcall 'list 'a '(b c d)) is the same as
+ (funcall 'list 'a 'b 'c 'd)
+.Lf listify "'x_count"
+.Re
+a list of x_count of the arguments to the current function (which
+must be a lexpr).
+.No
+normally arguments 1 through x_count are returned. 
+If x_count is negative then  a list of last abs(x_count) arguments are
+returned.
+.Lf map "'u_func 'l_arg1 ..."
+.Re
+l_arg1
+.No
+The function u_func is applied to successive sublists of the l_arg\fIi\fP.
+All sublists should have the same length.  
+.\".pg
+.Lf mapc "'u_func 'l_arg1 ..."
+.Re
+l_arg1.
+.No
+The function u_func is applied to successive elements of the argument 
+lists.
+All of the lists should have the same length.
+.Lf mapcan "'u_func 'l_arg1 ..."
+.Re
+nconc applied to the results of the functional evaluations.
+.No
+The function u_func is applied to successive elements of the 
+argument lists.
+All sublists should have the same length.
+.Lf mapcar "'u_func 'l_arg1 ..."
+.Re
+a list of the values returned from the functional application.
+.No
+the function u_func is applied to successive elements of the
+argument lists.
+All sublists should have the same length.
+.Lf mapcon "'u_func 'l_arg1 ..."
+.Re
+nconc applied to the results of the functional evaluation.
+.No
+the function u_func is applied to successive sublists of the
+argument lists.
+All sublists should have the same length.
+.Lf maplist "'u_func 'l_arg1 ..."
+.Re
+a list of the results of the functional evaluations.
+.No
+the function u_func is applied to successive sublists of the arguments
+lists.
+All sublists should have the same length.
+.lp
+Readers may find the following summary table useful in remembering
+the differences between the six mapping functions:
+
+.TS
+box;
+c | c s s.
+\      Value returned is
+
+.T&
+c | c c c.
+T{
+.na
+Argument to functional is
+.ad
+T}     l_arg1  list of results \fInconc\fP of results
+_
+.T&
+c | c c c.
+
+elements of list       mapc    mapcar  mapcan
+
+sublists       map     maplist mapcon
+.TE
+.sp 2v
+.Lf mfunction "t_entry 's_disc"
+.Re
+a lisp object of type binary composed of t_entry and s_disc.
+.No
+t_entry is a pointer to the machine code for a function, and s_disc is the
+discipline (e.g. lambda).
+.\".pg
+.Lf oblist
+.Re
+a list of all symbols on the oblist.
+.Lf or "[g_arg1 ... ]"
+.Re
+the value of the first non-null argument  or nil if all arguments 
+evaluate to nil.
+.No
+Evaluation proceeds left to right and stops as soon as one of the arguments
+evaluates to a non-null value.
+.Lf prog "l_vrbls g_exp1 ..."
+.Re
+the value explicitly given in a return form
+or else nil if no return is done by the time the last g_exp\fIi\fP is
+evaluated.
+.No
+the local variables are lambda bound to nil then the g_exp\fI\fP
+are evaluated from left to right.
+This is a prog body (obviously) and this means than 
+any symbols seen are not evaluated,
+instead they are treated as labels.
+This also means that return's and go's are allowed.
+.Lf prog1 "'g_exp1 ['g_exp2 ...]"
+.Re
+g_exp1
+.Lf prog2 "'g_exp1 'g_exp2 ['g_exp3 ...]"
+.Re
+g_exp2
+.No
+the forms are evaluated from left to right and the value of g_exp2 is
+returned.
+.Lf progn "'g_exp1 ['g_exp2 ...]"
+.Re
+the last g_exp\fIi\fP.
+.Lf progv "'l_locv 'l_initv g_exp1 ..."
+.Wh
+l_locv is a list of symbols and l_initv is a list of expressions.
+.Re
+the value of the last g_exp\fIi\fP evaluated.
+.No
+The expressions in l_initv are evaluated from left to right
+and then lambda-bound to the symbols in l_locv.
+If there are too few expressions in l_initv then the missing values
+are assumed to be nil.
+If there are too many expressions in l_initv then the extra ones are
+ignored (although they are evaluated).
+Then the g_exp\fIi\fP are evaluated left to right.
+The body of a progv is like the body of a progn, it is 
+.i not
+a prog body.
+(C.f. 
+.i let )
+.Lf purcopy "'g_exp"
+.Re
+a copy of g_exp with new pure cells allocated wherever possible.
+.No
+pure space is never swept up by the garbage collector, so this should
+only be done on expressions which are not likely to become garbage
+in the future.
+In certain cases, data objects in pure space become read-only after
+a 
+.i dumplisp
+and then an attempt to modify the object will result in an illegal memory
+reference.
+.Lf purep "'g_exp"
+.Re
+t iff the object g_exp is in pure space.
+.Lf putd "'s_name 'u_func"
+.Re
+u_func
+.Se
+this sets the function binding of symbol s_name to u_func.
+.Lf return "['g_val]"
+.Re
+g_val (or nil if g_val is not present) from the enclosing prog or do body.
+.No
+this form is only valid in the context of a prog or do body.
+.Lf selectq "'g_key-form [l_clause1 ...]"
+.No
+This function is just like \fIcaseq\fP (see above), except that
+the symbol \fBotherwise\fP has the same semantics as the
+symbol \fBt\fP, when used as a comparator.
+.Lf setarg "'x_argnum 'g_val"
+.Wh
+x_argnum is greater than zero and less than or equal to the number of
+arguments to the lexpr.
+.Re
+g_val
+.Se
+the lexpr's x_argnum'th argument is set to g-val.
+.No
+this can only be used within the body of a lexpr.
+.Lf throw "'g_val [s_tag]"
+.Wh
+if s_tag is not given, it is assumed to be nil.
+.Re
+the value of \fI(*throw 's_tag 'g_val)\fP.
+.Lf *throw "'s_tag 'g_val"
+.Re
+g_val from the first enclosing catch with 
+the tag s_tag or with no tag at all.
+.No
+this is used in conjunction with 
+.i *catch
+to cause a clean jump to an enclosing context.
+.Lf unwind-protect "g_protected [g_cleanup1 ...]"
+.Re
+the result of evaluating g_protected.
+.No
+Normally g_protected is evaluated and its value
+remembered, then the g_cleanup\fIi\fP
+are evaluated and finally the saved value of g_protected is returned.
+If something should happen when evaluating g_protected which causes
+control to pass through g_protected  and thus through
+the call to the unwind-protect,
+then the g_cleanup\fIi\fP will still be evaluated.
+This is useful if g_protected does  something sensitive which 
+must be cleaned up whether or not g_protected completes.
diff --git a/usr/lisp/ch6.n b/usr/lisp/ch6.n
new file mode 100644 (file)
index 0000000..eeceb43
--- /dev/null
@@ -0,0 +1,694 @@
+." $Header: ch6.n,v 1.4 83/07/21 21:08:16 sklower Exp $
+.Lc System\ Functions 6
+.pp
+This chapter describes the functions used to interact
+with internal components of the Lisp system and operating system.
+.Lf allocate "'s_type 'x_pages"
+.Wh
+s_type is one of the 
+.Fr
+data types described in \(sc1.3.
+.Re
+x_pages.
+.Se
+.Fr
+attempts to allocate x_pages of type s_type.
+If there aren't x_pages of memory left, no space will be 
+allocated and an error will occur.
+The storage that is allocated is not given to the caller, instead it is 
+added to the free storage list of s_type.
+The functions
+.i segment
+and 
+.i small-segment 
+allocate blocks  of storage and return it to the caller.
+.Lf argv "'x_argnumb"
+.Re
+a symbol whose pname is the x_argnumb\fIth\fP argument (starting at 0)
+on the command
+line which invoked the current lisp.
+.No
+if x_argnumb is less than zero, a fixnum whose value is the number of arguments
+on the command line is returned.
+\fI(argv\ 0)\fP returns the name of the lisp you are running.
+.Lf baktrace 
+.Re
+nil
+.Se
+the lisp runtime stack is examined and the name of (most) of the functions
+currently in execution are printed, most active first.
+.No
+this will occasionally miss the names of compiled lisp functions due to
+incomplete information on the stack.
+If you are tracing compiled code, then \fIbaktrace\fP won't be able
+to interpret the stack unless 
+.i (sstatus\ translink\ nil)
+was done.
+See the function 
+.i showstack 
+for another way of printing the lisp runtime
+stack.
+.Lf boundp "'s_name"
+.Re
+nil  if s_name is unbound, that is it has never be given a value.
+If x_name has the value g_val, then (nil\ .\ g_val) is returned.
+.\".pg
+.Lf chdir "'s_path"
+.Re
+t iff the system call succeeds.
+.Se
+the current directory set to s_path. 
+Among other things, this will affect the default location
+where the input/output functions look for and create files.
+.No
+\fIchdir\fP follows the standard UNIX conventions, if s_path does not begin
+with a slash, the default path is changed to the current path with
+s_path appended.
+.i Chdir
+employs tilde-expansion (discussed in Chapter 5).
+.Lf command-line-args
+.Re
+a list of the arguments typed on the command line, either to the
+lisp interpreter, or saved lisp dump, or application compiled
+with the autorun option (liszt -r).
+.Lf deref "'x_addr"
+.Re
+The contents of x_addr, when thought of as a longword memory
+location.
+.No
+This may be useful in constructing arguments to C functions
+out of `dangerous' areas of memory.
+.Lf dumplisp "s_name"
+.Re
+nil
+.Se
+the current lisp is dumped to the named file.
+When s_name is executed, you will be in a lisp in the
+same state as when the dumplisp was done.
+.No
+dumplisp will fail if one tries to 
+write over the current running file. 
+UNIX does not allow you to modify the file you are running.
+.Lf eval-when "l_time g_exp1 ..."
+.Se
+l_time may contain any combination of the symbols
+.i load ,
+.i eval ,
+and
+.i compile .
+The effects of load and compile is discussed in \(sc12.3.2.1
+compiler.
+If eval is present however, this simply means that the expressions g_exp1
+and so on are evaluated from left to right.
+If eval is not present, the forms are not evaluated.
+.Lf exit "['x_code]"
+.Re
+nothing (it never returns).
+.Se
+the lisp system dies with exit code x_code or 0 if x_code is not
+specified.
+.Lf fake "'x_addr"
+.Re
+the lisp object at address x_addr.
+.No
+This is intended to be used by people debugging the lisp system.
+.Lf fork 
+.Re
+nil to the child process and the process number of the child to 
+the parent.
+.Se
+A copy of the current lisp system is made in memory and both
+lisp systems now begin to run.
+This function can be used interactively to temporarily
+save the state of Lisp (as shown below), but you must be careful that only one
+of the lisp's interacts with the terminal after the fork.
+The
+.i wait 
+function is useful for this.
+.Eb
+\-> \fI(setq foo 'bar)\fP              ;; set a variable
+bar
+\-> \fI(cond ((fork)(wait)))\fP        ;; duplicate the lisp system and
+nil                            ;; make the parent wait
+\-> \fIfoo\fP                          ;; check the value of the variable
+bar
+\-> \fI(setq foo 'baz)\fP              ;; give it a new value
+baz
+\-> \fIfoo\fP                          ;; make sure it worked
+baz
+\-> \fI(exit)\fP                       ;; exit the child
+(5274 . 0)                     ;; the \fIwait\fP function returns this
+\-> \fIfoo\fP                          ;; we check to make sure parent was
+bar                            ;; not modified.
+.Ee
+.Lf gc
+.Re
+nil
+.Se
+this causes a garbage collection.
+.No
+The function
+.i gcafter
+is not called automatically after this function finishes.
+Normally the user doesn't have to call
+.i gc
+since
+garbage collection occurs automatically whenever internal free lists
+are exhausted.
+.Lf gcafter "s_type"
+.Wh
+s_type is one of the 
+.Fr
+data types listed in \(sc1.3.
+.No
+this function is called by the garbage collector
+after a garbage collection which was caused by running out of 
+data type s_type.
+This function should determine if more space need be allocated
+and if so should allocate it.
+There is a default gcafter function but users who want control over
+space allocation can define their own -- but note that it must be
+an nlambda.
+.Lf getenv "'s_name"
+.Re
+a symbol whose pname is the value of s_name in the current 
+UNIX environment.
+If s_name doesn't exist in the current environment, a symbol with a null pname
+is returned.
+.Lf hashtabstat
+.Re
+a list of fixnums representing the number of symbols in each bucket of
+the oblist.
+.No
+the oblist is stored a hash table of buckets.
+Ideally there would be the same number of symbols in each bucket.
+.Lf help "[sx_arg]"
+.Se
+If sx_arg is a symbol then
+the portion of this manual beginning with the description of sx_arg
+is printed on the terminal.
+If sx_arg is  a fixnum or the name of one of the appendicies, that
+chapter or appendix is printed on the terminal.
+If no argument is provided, 
+.i help
+prints the options that it recognizes.
+The program `more' is used to print the manual on the terminal; it will
+stop after each page and will continue after the space key is pressed.
+.Lf include "s_filename"
+.Re
+nil
+.Se
+The given filename is 
+.i load ed
+into the lisp.
+.No
+this is similar to load except the argument is not evaluated.
+Include means something special to the compiler.
+.Lf include-if "'g_predicate s_filename"
+.Re
+nil
+.Se
+This has the same effect as include, but is only actuated
+if the predicate is non-nil.
+.Lf includef "'s_filename"
+.Re
+nil
+.Se
+this is the same as 
+.i include
+except the argument is evaluated.
+.Lf includef-if "'g_predicate s_filename"
+.Re
+nil
+.Se
+This has the same effect as includef, but is only actuated
+if the predicate is non-nil.
+.Lf maknum "'g_arg"
+.Re
+the address of its argument converted into a fixnum.
+.Lf monitor "['xs_maxaddr]"
+.Re
+t
+.Se
+If xs_maxaddr is t then profiling of the entire lisp system is begun.
+If xs_maxaddr is a fixnum then profiling is done only up to address
+xs_maxaddr.
+If xs_maxaddr is not given, then profiling is stopped and the data
+obtained is written to the file 'mon.out' where it can be analyzed
+with the UNIX 'prof' program.
+.No
+this function only works if the lisp system has been compiled
+in a special way, otherwise, an error is invoked.
+.Lf opval "'s_arg ['g_newval]"
+.Re
+the value associated with s_arg before the call.
+.Se
+If g_newval is specified, the value associated with s_arg is changed to
+g_newval.
+.No
+\fIopval\fP keeps track of storage allocation. If s_arg is one of the data types
+then \fIopval\fP will return a list of three fixnums representing the number of
+items of that type in use, the number of pages allocated and the number
+of items of that type per page.  
+You should never try to change the value \fIopval\fP associates
+with a data type using
+\fIopval\fP.
+.br
+If s_arg is 
+.i pagelimit
+then 
+.i opval 
+will return (and set if g_newval is given)
+the maximum amount of lisp data pages
+it will allocate.
+This limit should remain small unless you know your program requires 
+lots of space as this limit will catch programs in infinite loops which
+gobble up memory.
+.Lf *process "'st_command ['g_readp ['g_writep]]"
+.Re
+either a fixnum if one argument is given, or a list of two ports and a
+fixnum if two or three arguments are given.
+.No
+\fI*process\fP starts another process by passing st_command to the shell
+(it first tries /bin/csh, then it tries /bin/sh if /bin/csh doesn't exist).
+If only one argument is given to \fI*process\fP,
+\fI*process\fP waits for the new
+process to die and then returns the exit code of the new process.
+If more two or three arguments are given, \fI*process\fP starts the process
+and then returns a list which, depending on the value of g_readp
+and g_writep, may contain i/o ports for communcating with the new
+process.
+If g_writep is non-null, then a port will be created which the lisp program
+can use to send characters to the new process.
+If g_readp is non-null, then a port will be created which the lisp program
+can use to read characters from the new process.
+The value returned by \fI*process\fP is (readport\ writeport\ pid)
+where readport and writeport are either nil or a port based on the value
+of g_readp and g_writep.  Pid is the process id of the new process.
+Since it is hard to remember the order of g_readp and g_writep, the
+functions \fI*process-send\fP and \fI*process-receive\fP were written to
+perform the common functions.
+.Lf *process-receive "'st_command"
+.Re
+a port which can be read.
+.Se
+The command st_command is given to the shell and it is started running in the
+background.
+The output of that command is available for reading via the port returned.
+The input of the command process is set to /dev/null.
+.Lf *process-send "'st_command"
+.Re
+a port which can be written to.
+.Se
+The command st_command is given to the shell and it is started runing in the
+background.
+The lisp program can provide input for that command
+by sending characters to the port returned by this function.
+The output of the command process is set to /dev/null.
+.Lf process "s_pgrm [s_frompipe s_topipe]"
+.Re
+if the optional arguments are
+not present a fixnum which is the exit code when s_prgm dies.
+If the optional arguments are present, it returns a fixnum which
+is the process id of the child.
+.No
+This command is obsolete.
+New programs should use one of the \fI*process\fP commands
+given above.
+.Se
+If s_frompipe and s_topipe are given, they are bound to 
+ports which are pipes which
+direct characters from 
+.Fr
+to the new process
+and to
+.Fr
+from the new process respectively.
+.i Process
+forks a process named s_prgm and waits for it to die iff there
+are no pipe arguments given.
+.Lf ptime 
+.Re
+a list of two elements, the first is the amount of processor time used
+by the lisp system so far, the 
+second is the amount of time used by the garbage collector so far.
+.No
+the time is measured in those units used by the
+.i times (2)
+system call, usually 60\fIth\fPs of a second.
+The first number includes the second number.
+The amount of time used by garbage collection is not recorded
+until the first call to ptime.
+This is done to prevent overhead when the user is not interested in
+garbage collection times.
+.Lf reset
+.Se
+the lisp runtime stack is cleared and the system restarts at the top level 
+by executing a \fI(funcall\ top-level\ nil)\fP.
+.Lf restorelisp "'s_name"
+.Se
+this reads in file s_name (which was created by 
+.i savelisp )
+and then does a \fI(reset)\fP.
+.No
+This is only used on VMS systems where 
+.i dumplisp
+cannot be used.
+.Lf retbrk "['x_level]
+.Wh
+x_level is a small integer of either sign.
+.Se
+The default error handler keeps a notion of the current level
+of the error caught.  If x_level is negative, control is thrown
+to this default error handler whose level is that many less than
+the present, or to \fItop-level\fP if there aren't enough.
+If x_level is non-negative, control is passed to the handler at
+that level.  If x_level is not present, the value -1 is taken by
+default.
+.Lf *rset "'g_flag"
+.Re
+g_flag
+.Se
+If g_flag is non nil then the lisp system will maintain extra information
+about calls to \fIeval\fP and \fIfuncall\fP.
+This record keeping slows down the evaluation but this is 
+required  for the functions
+\fIevalhook\fP, \fIfuncallhook\fP, and \fIevalframe\fP to work. 
+To debug compiled lisp code the transfer tables should be unlinked:
+\fI(sstatus\ translink\ nil)\fP
+.Lf savelisp "'s_name"
+.Re
+t
+.Se
+the state of the Lisp system is saved in the file s_name.
+It can be read in by 
+.i restorelisp .
+.No
+This is only used on VMS systems where 
+.i dumplisp
+cannot be used.
+.Lf segment "'s_type 'x_size"
+.Wh
+s_type is one of the data types given in \(sc1.3
+.Re
+a segment of contiguous lispvals of type s_type.
+.No
+In reality, 
+.i segment 
+returns a new data cell of type s_type and allocates
+space for x_size \- 1 more s_type's beyond the one returned.
+.i Segment 
+always allocates new space and does so in 512 byte chunks.
+If you ask for 2 fixnums, segment will actually allocate 128 of them
+thus wasting 126 fixnums.
+The function
+.i small-segment
+is a smarter space allocator and should be used whenever possible.
+.Lf shell
+.Re
+the exit code of the shell when it dies.
+.Se
+this forks a new shell and returns when the shell dies.
+.Lf showstack
+.Re
+nil
+.Se
+all forms currently in evaluation are printed, beginning with the most recent.
+For compiled code the most that 
+showstack will show is the function name and it may miss
+some functions.
+.Lf signal "'x_signum 's_name"
+.Re
+nil if no previous call to signal has been made, or the previously
+installed s_name.
+.Se
+this declares that the function named s_name 
+will handle the signal number x_signum.
+If s_name is nil, the signal is ignored.  Presently only
+four UNIX signals are caught, they and their numbers are:
+Interrupt(2), Floating exception(8), Alarm(14), and
+Hang-up(1).
+.Lf sizeof "'g_arg"
+.Re
+the number of bytes required to store one object of type g_arg, encoded
+as a fixnum.
+.Lf small-segment "'s_type 'x_cells"
+.Wh
+s_type is one of fixnum, flonum and value.
+.Re
+a segment of x_cells data objects of type s_type.
+.Se
+This may call
+.i segment
+to allocate new space or it may be able to fill the request on a page
+already allocated.
+The value returned by 
+.i small-segment 
+is usually stored in the data subpart
+of an array object.
+.Lf sstatus "g_type g_val"
+.Re
+g_val
+.Se
+If g_type is not one of the special sstatus codes described in the 
+next few pages
+this simply sets g_val as the value of status 
+type g_type in the system status property list.
+.Lf sstatus\ appendmap "g_val"
+.Re
+g_val
+.Se
+If g_val is non-null when 
+.i fasl
+is told to create a load map, it will append to the file name given in
+the 
+.i fasl
+command, rather than creating a new map file.
+The initial value is nil.
+.Lf sstatus\ automatic-reset "g_val"
+.Re
+g_val
+.Se
+If g_val is non-null when an error occurs which no one wants to 
+handle, a 
+.i reset
+will be done instead of entering a primitive internal break loop.
+The initial value is t.
+.Lf sstatus\ chainatom "g_val"
+.Re
+g_val
+.Se
+If g_val is non nil and a 
+.i car
+or 
+.i cdr
+of a symbol is done, then nil will be returned instead of an error
+being signaled.
+This only affects the interpreter, not the compiler.
+The initial value is nil.
+.Lf sstatus\ dumpcore "g_val"
+.Re
+g_val
+.Se
+If g_val is nil, 
+.Fr 
+tells UNIX that a segmentation violation or 
+bus error should cause a core dump.
+If g_val is non nil then 
+.Fr
+will catch those errors and print a message advising the user to reset.
+.No
+The initial value for this flag is nil, and only those knowledgeable of
+the innards of the lisp system should ever set this flag non nil.
+.Lf sstatus\ dumpmode "x_val"
+.Re
+x_val
+.Se
+All subsequent 
+.i dumplisp 's
+will be done in mode x_val.
+x_val may be either 413 or 410 (decimal).
+.No
+the advantage of mode 413 is that the dumped Lisp can be demand paged in when
+first started, which will make it start faster and disrupt other users less.
+The initial value is 413.
+.Lf sstatus\ evalhook "g_val"
+.Re
+g_val
+.Se
+When g_val is non nil, this enables the 
+evalhook and funcallhook traps in the evaluator.
+See \(sc14.4 for more details.
+.Lf sstatus\ feature "g_val"
+.Re
+g_val
+.Se
+g_val is added to the \fI(status\ features)\fP list, 
+.Lf sstatus\ gcstrings "g_val"
+.Re
+g_val
+.Se
+if g_val is non-null, and if string garbage collection was enabled when
+the lisp system was compiled, string space will be garbage collected.
+.No
+the default value for this is nil since in most applications garbage
+collecting strings is a waste of time.
+.Lf sstatus\ ignoreeof "g_val"
+.Re
+g_val
+.Se
+If g_val is non-null when
+an end of file (CNTL-D on UNIX) is typed to the standard top-level interpreter,
+it will be ignored rather then cause the lisp system to exit.
+If the the standard input is a file or pipe then this has no effect,
+an EOF will always cause lisp to exit.
+The initial value is nil.
+.Lf sstatus\ nofeature "g_val"
+.Re
+g_val
+.Se
+g_val is removed from the status features list if it was present.
+.Lf sstatus\ translink "g_val"
+.Re
+g_val
+.Se
+If g_val is nil then all transfer tables are cleared and further calls
+through the transfer table will not cause the fast links to be set up.
+If g_val is the symbol 
+.i on
+then all possible transfer table entries will be linked and the flag
+will be set to cause fast links to be set up dynamically.
+Otherwise all that is done is to set the flag to cause fast links
+to be set up dynamically.
+The initial value is nil.
+.No
+For a discussion of transfer tables, see \(sc12.8.
+.Lf sstatus\ uctolc "g_val"
+.Re
+g_val
+.Se
+If g_val is not nil then all unescaped capital letters 
+in symbols read by the reader will be converted to lower case.
+.No
+This allows 
+.Fr
+to be compatible with single case lisp
+systems (e.g. Maclisp, Interlisp and UCILisp).
+.Lf status "g_code"
+.Re
+the value associated with the status code g_code
+if g_code is not one of the special cases given below
+.Lf status\ ctime 
+.Re
+a symbol whose print name is the current time and date.
+.Ex
+\fI(status ctime)\fP = |Sun Jun 29 16:51:26 1980|
+.No
+This has been made obsolete by \fItime-string\fP, described below.
+.Lf status\ feature "g_val"
+.Re
+t iff g_val is in the status features list.
+.Lf status\ features 
+.Re
+the value of the features code, which is a list of features which
+are present in this system.
+You add to this list with \fI(sstatus\ feature\ 'g_val)\fP
+and test if feature g_feat is present with \fI(status\ feature\ 'g_feat)\fP.
+.Lf status\ isatty 
+.Re
+t iff the standard input is a terminal.
+.Lf status\ localtime
+.Re
+a list of fixnums representing the current time.
+.Ex
+\fI(status localtime)\fP =  (3 51 13 31 6 81 5 211 1)
+.br
+means 3\fIrd\fP second, 51\fIst\fP minute, 13\fIth\fP hour (1 p.m),
+31\fIst\fP day, month 6 (0\ =\ January), year 81 (0\ =\ 1900),
+day of the week 5 (0\ =\ Sunday), 211\fIth\fP day of the year
+and daylight savings time is in effect.
+.Lf status\ syntax "s_char"
+.No
+This function should not be used.
+See the description of
+.i getsyntax
+(in Chapter 7) for a replacement.
+.Lf status\ undeffunc
+.Re
+a list of all functions which transfer table entries point to but which
+are not defined at this point.
+.No
+Some of the undefined functions listed could be arrays which have yet
+to be created.
+.Lf status\ version
+.Re
+a string which is the current lisp version name.
+.Ex
+\fI(status version)\fP = "Franz Lisp, Opus 38.61"
+.Lf syscall "'x_index ['xst_arg1 ...]"
+.Re
+the result of issuing the UNIX system call number x_index with arguments
+xst_arg\fIi\fP.
+.No
+The UNIX system calls are described in section 2 of the
+UNIX Programmer's manual. 
+If xst_arg\fIi\fP is a fixnum, then 
+its value is passed as an argument, if it is a symbol then 
+its pname is passed and finally if it is a string then the string itself
+is passed as an argument.
+Some useful syscalls are:
+.br
+\fI(syscall\ 20)\fP returns process id.
+.br
+\fI(syscall\ 13)\fP returns the number of seconds since Jan 1, 1970.
+.br
+\fI(syscall\ 10\ 'foo)\fP will unlink (delete) the file foo.
+.Lf sys:access "'st_filename 'x_mode"
+.Lx sys:chmod "'st_filename 'x_mode"
+.Lx sys:gethostname
+.Lx sys:getpid
+.Lx sys:getpwnam 'st_username
+.Lx sys:link "'st_oldfilename 'st_newfilename"
+.Lx sys:time
+.Lx sys:unlink 'st_filename
+.No
+We have been warned that the actual system call numbers may vary
+among different UNIX systems.  Users concerned about portability
+may wish to use this group of functions.
+Another advantage is that tilde-expansion is performed on
+all filename arguments.
+These functions do what is described
+in the system call section of your UNIX manual.
+.br
+.sp
+.i sys:getpwname
+returns a vector of four entries from the password file, being
+the user name, user id, group id, and home directory.
+.Lf time-string "['x_seconds]"
+.Re
+an ascii string, giving the time and date which was
+x_seconds after UNIX's idea of creation
+(Midnight, Jan 1, 1970 GMT).  If no argument is given,
+time-string returns the current date.
+This supplants \fI(status ctime)\fP, and may be used
+to make the results of \fIfilestat\fP more intelligible.
+.Lf top-level
+.Re
+nothing (it never returns)
+.No
+This function is the top-level read-eval-print loop.
+It never returns any value.
+Its main utility is that if you redefine it, and do a (reset) then the
+redefined (top-level) is then invoked.
+The default top-level for Franz, allow one to specify
+his own printer or reader, by binding the symbols \fBtop-level-printer\fP
+and \fBtop-level-reader\fP.
+One can let the default top-level do most of the drudgery in catching
+.i reset 's,
+and reading in .lisprc files,
+by binding the symbol \fBuser-top-level\fP, to a routine that
+concerns itself only with the read-eval-print loop.
+.Lf wait
+.Re
+a dotted pair \fI(processid . status)\fP when the
+next child process dies. 
diff --git a/usr/lisp/ch8.n b/usr/lisp/ch8.n
new file mode 100644 (file)
index 0000000..11f6129
--- /dev/null
@@ -0,0 +1,892 @@
+." $Header: ch8.n 1.4 83/07/27 15:12:22 layer Exp $
+.Lc Functions,\ Fclosures,\ and\ Macros 8
+.sh 2 valid\ function\ objects 8
+.pp
+There are many different objects which can occupy the function field of 
+a symbol object.
+Table 8.1, on the following page,
+shows all of the possibilities, how to recognize them,
+and where to look for documentation.
+.(z
+.sp 1v
+.TS
+box center ;
+c | c | c .
+informal name  object type     documentation 
+=
+interpreted    list with \fIcar\fP     8.2
+lambda function        \fIeq\fP to lambda
+_
+interpreted    list with \fIcar\fP     8.2
+nlambda function       \fIeq\fP to nlambda
+_
+interpreted    list with \fIcar\fP     8.2
+lexpr function \fIeq\fP to lexpr
+_
+interpreted    list with \fIcar\fP     8.3
+macro  \fIeq\fP to macro
+_
+fclosure       vector with \fIvprop\fP 8.4
+       \fIeq\fP to fclosure
+_
+compiled       binary with discipline  8.2
+lambda or lexpr        \fIeq\fP to lambda
+function
+_
+compiled       binary with discipline  8.2
+nlambda function       \fIeq\fP to nlambda
+_
+compiled       binary with discipline  8.3
+macro  \fIeq\fP to macro
+_
+foreign        binary with discipline  8.5
+subroutine     of \*(lqsubroutine\*(rq\*[\(dg\*]
+_
+foreign        binary with discipline  8.5
+function       of \*(lqfunction\*(rq\*[\(dg\*]
+_
+foreign        binary with discipline  8.5
+integer function       of \*(lqinteger-function\*(rq\*[\(dg\*]
+_
+foreign        binary with discipline  8.5
+real function  of \*(lqreal-function\*(rq\*[\(dg\*]
+_
+foreign        binary with discipline  8.5
+C function     of \*(lqc-function\*(rq\*[\(dg\*]
+_
+foreign        binary with discipline  8.5
+double function        of \*(lqdouble-c-function\*(rq\*[\(dg\*]
+_
+foreign        binary with discipline  8.5
+structure function     of \*(lqvector-c-function\*(rq\*[\(dg\*]
+_
+array  array object    9
+.TE
+.tl ''Table 8.1''
+.(f
+\*[\(dg\*]Only the first character of the string is significant (i.e \*(lqs\*(rq
+is ok for \*(lqsubroutine\*(rq)
+.)f
+.)z
+.br
+.sh 2 functions
+.pp
+The basic Lisp function is the lambda function.
+When a lambda function is called, the actual arguments are
+evaluated from left to right and are lambda-bound to the
+formal parameters of the lambda function.
+.pp
+An nlambda function is usually used for functions which are invoked
+by the user at top level.
+Some built-in functions which evaluate their arguments in special ways are
+also nlambdas (e.g \fIcond\fP, \fIdo\fP, \fIor\fP).
+When an nlambda function is called, the list of unevaluated arguments
+is lambda bound to the single formal parameter of the nlambda function.
+.pp
+Some programmers will use an nlambda function 
+when they are not sure how many arguments
+will be passed.
+Then, the first thing the nlambda function does is map \fIeval\fP over
+the list of unevaluated arguments it has been passed.
+This is usually the wrong thing to do, as it will not work compiled if
+any of the arguments are local variables. 
+The solution is to use a lexpr.
+When a lexpr function is called, the arguments
+are evaluated and a fixnum whose value is
+the number of arguments is lambda-bound to the single
+formal parameter of the lexpr function.
+The lexpr can then access the arguments using the \fIarg\fP function.
+.pp
+When a function is compiled,
+.i special 
+declarations may be needed to 
+preserve its behavior.
+An argument is not lambda-bound to the name of
+the corresponding formal parameter 
+unless that formal parameter has been declared 
+.i special 
+(see \(sc12.3.2.2).
+.pp
+Lambda and lexpr functions both compile into a binary object with
+a discipline of lambda.
+However, a compiled lexpr still acts like an interpreted lexpr.
+.sh 2 macros
+.pp
+An important feature of Lisp 
+is its ability to manipulate programs as data.
+As a result of this, most Lisp implementations
+have very powerful macro facilities.
+The Lisp language's macro facility
+can be used to incorporate popular features of the other
+languages into Lisp.
+For example, there are macro packages 
+which allow one to create records (ala Pascal) 
+and refer to elements of those records by the field names.
+The 
+.i struct
+package imported from Maclisp does this.
+Another popular use for macros is to create more readable control 
+structures which expand into 
+.i cond , 
+.i or 
+and 
+.i and .
+One such example is the If macro.
+It allows you to write
+.sp 1v
+.nf
+.ft I
+(If (equal numb 0) then (print 'zero) (terpr)
+\ elseif (equal numb 1) then (print 'one) (terpr)
+\ else (print '|I give up|))
+.ft P
+.sp 1v
+which expands to 
+.sp 1v
+.ft I
+(cond 
+\ \ \ \ ((equal numb 0) (print 'zero) (terpr))
+\ \ \ \ ((equal numb 1) (print 'one) (terpr))
+\ \ \ \ (t (print '|I give up|)))
+.ft P
+.sp 1v
+.fi
+.sh 3  macro\ forms
+.pp
+A macro is a function which accepts a Lisp expression as input and returns
+another Lisp expression.
+The action the macro takes is called macro expansion.
+Here is a simple example:
+.sp 1v
+.nf
+\-> \fI(def first (macro (x) (cons 'car (cdr x))))\fP
+first
+\-> \fI(first '(a b c))\fP
+a
+\-> \fI(apply 'first '(first '(a b c)))\fP
+(car '(a b c))
+.fi
+.sp 1v
+The first input line defines a macro called 
+.i first .
+Notice that the macro has one formal parameter, \fIx\fP.  
+On the second input line, we ask the interpreter to evaluate
+\fI(first\ '(a\ b\ c))\fP.
+.i Eval 
+sees that 
+.i first
+has a function definition of type macro, so it evaluates 
+.i first 's 
+definition,
+passing to 
+.i first ,
+as an argument, the form 
+.i eval 
+itself
+was trying to
+evaluate: \fI(first\ '(a\ b\ c))\fP.
+The 
+.i first 
+macro chops off the car of the argument with
+.i cdr ,
+cons' a 
+.i car
+at the beginning of the list and returns \fI(car\ '(a\ b\ c))\fP,
+which
+.i eval 
+evaluates.
+The value
+.i a
+is returned as the value of \fI(first\ '(a\ b\ c))\fP.
+Thus whenever 
+.i eval
+tries to evaluate a list whose car has a macro definition
+it ends up doing (at least) two operations, the first of which
+is a call to the macro
+to let it macro expand the form, and the other is the evaluation of the
+result of the macro.
+The result of the macro may be yet another call to a macro, so 
+.i eval
+may have to do even more evaluations until it can finally determine
+the  value of an expression.
+One way to see how a macro will expand is to use
+.i apply
+as shown on the third input line above.
+.sh +0 defmacro
+.pp
+The macro 
+.i defmacro
+makes it easier to define macros because it allows you to name the arguments
+to the macro call.
+For example, suppose we find ourselves often writing code like
+\fI(setq\ stack\ (cons\ newelt\ stack)\fP.
+We could define a macro named \fIpush\fP to do this for us.
+One way to define it is:
+.nf
+.sp 1v
+\-> \fI(de\kAf push 
+\h'|\nAu'(macro (x) (list 'setq (caddr x) (list 'cons (cadr x) (caddr x)))))\fP
+push
+.fi
+.sp 1v
+then \fI(push\ newelt\ stack)\fP will expand to the form mentioned above.
+The same macro written using defmacro would be:
+.nf
+.sp 1v
+\->\fI\kA (defmacro push (value stack)
+  \h'|\nAu'(list 'setq ,stack (list 'cons ,value ,stack)))\fP
+push
+.fi
+.sp 1v
+Defmacro allows you to name the arguments of the macro call, and makes the 
+macro definition look more like a function definition.
+.sh +0 the\ backquote\ character\ macro
+.pp
+The default syntax for 
+.Fr
+has four characters with associated character macros.
+One is semicolon for comments.
+Two others are the backquote and comma which are
+used by the backquote character
+macro.
+The fourth is the sharp sign macro described in the next section.
+.pp
+The backquote macro is used to create lists where many of the elements are
+fixed (quoted). 
+This makes it very useful for creating macro definitions.
+In the simplest case, a backquote acts just like a single quote:
+.sp 1v
+.nf
+\->\fI`(a b c d e)\fP
+(a b c d e)
+.fi
+.sp 1v
+If a comma precedes an element of a backquoted list then that element is
+evaluated and its value is put in the list.
+.sp 1v
+.nf
+\->\fI(setq d '(x y z))\fP
+(x y z)
+\->\fI`(a b c ,d e)\fP
+(a b c (x y z) e)
+.fi
+.sp 1v
+If a comma followed by an at sign precedes an element in a backquoted list,
+then that element is evaluated and spliced into the list with 
+.i append .
+.nf
+.sp 1v
+\->\fI`(a b c ,@d e)\fP
+(a b c x y z e)
+.sp 1v
+.fi
+Once a list begins with a backquote, the commas may appear anywhere in the
+list as this example shows:
+.nf
+.sp 1v
+\->\fI`(a b (c d ,(cdr d)) (e f (g h ,@(cddr d) ,@d)))\fP
+(a b (c d (y z)) (e f (g h z x y z)))
+.sp 1v
+.fi
+It is also possible and sometimes even useful to use the 
+backquote macro within itself.
+As a final demonstration of the backquote macro, we shall define the 
+first and push macros using all the power at our disposal: defmacro
+and the backquote macro.
+.sp 1v
+.nf
+\->\fI(defmacro first (list) `(car ,list))\fP
+first
+\->\fI(defmacro push (value stack) `(setq ,stack (cons ,value ,stack)))\fP
+stack
+.fi
+.sh +0 sharp\ sign\ character\ macro
+.pp
+The sharp sign macro can perform a number of
+different functions  at read time.
+The character directly following the sharp sign determines which function
+will be done, and following Lisp s-expressions may serve as arguments.
+.sh +1 conditional\ inclusion
+.lp
+If you plan to run one source file in more than one environment then 
+you may want to some pieces of code to be included  or not included
+depending on the environment.  
+The C language uses \*(lq#ifdef\*(lq and \*(lq#ifndef\*(rq for this 
+purpose, and Lisp uses \*(lq#+\*(rq and \*(lq#\-\*(rq.
+The environment that the sharp sign macro checks is the 
+\fI(status\ features)\fP list which is initialized when the Lisp
+system is built  and which may be  altered by 
+\fI(sstatus\ feature\ foo)\fP and \fI(sstatus\ nofeature\ bar)\fP
+The form  of conditional inclusion is
+.br
+.tl ''\fI#+when what\fP''
+where 
+.i when 
+is either a symbol or an expression involving symbols and the functions
+.i and ,
+.i or ,
+and
+.i not .
+The meaning is that 
+.i what
+will only be read in if  
+.i when
+is true.
+A symbol in 
+.i when
+is true only if it appears in the 
+.i (status\ features)
+list.
+.Eb
+; suppose we want to write a program which references a file
+; and which can run at ucb, ucsd and cmu where the file naming conventions
+; are different.
+;
+\-> \fI(de\kAfun howold (name)
+   \h'|\nAu'\kC(terpr)
+   \h'|\nCu'\kB(load #\kA+(or ucb ucsd) "/usr/lib/lisp/ages.l"
+          \h'|\nAu'#+cmu "/usr/lisp/doc/ages.l")
+   \h'|\nBu'\kA(patom name)
+   \h'|\nBu'\kA(patom " is ")
+   \h'|\nAu'\kB(print (cdr (assoc name agefile)))
+   \h'|\nBu'\kA(patom "years old")
+   \h'|\nAu'(terpr))\fP
+.Ee
+The form
+.br
+.tl ''\fI#\-when what\fP''
+is equivalent to
+.br
+.tl ''\fI#+(not when) what\fP''
+.sh +0 fixnum\ character\ equivalents
+.lp
+When working with fixnum equivalents of characters, it is often hard to
+remember the number corresponding to a character.
+The form
+.br
+.tl ''\fI#/c\fP''
+is equivalent to the fixnum representation of character c.
+.Eb
+; a function which returns t if the user types y else it returns nil.
+;
+\-> \fI(de\kBfun yesorno nil
+   \h'|\nBu'(progn \kA(ans)
+          \h'|\nAu'\kB(setq ans (tyi))
+          \h'|\nBu'(cond \kA((equal ans #/y) t)
+                \h'|\nAu'(t nil))))\fP
+.Ee
+.sh +0 read\ time\ evaluation
+.lp
+Occasionally you want to express a constant as a Lisp expression, yet you
+don't want to pay the penalty of evaluating this expression each time it
+is referenced.
+The form
+.br
+.tl ''\fI#.expression\fP''
+evaluates the expression at read time and returns its value.
+.Eb
+; a function to test if any of bits 1 3 or 12 are set in a fixnum.
+;
+\-> \fI(de\kCfun testit (num)
+   \h'|\nCu'(cond \kA(\kB(zerop (boole 1 num #.(+ (lsh 1 1) (lsh 1 3) (lsh 1 12))))
+          \h'|\nBu'nil)
+         \h'|\nAu'(t t)))\fP
+.Ee
+.sh 2 fclosures
+.pp
+Fclosures are a type of functional object.
+The purpose is to remember the values of some variables 
+between invocations of the functional object and to protect this
+data from being inadvertently overwritten by other Lisp functions.
+Fortran programs usually exhibit this behavior for their variables.
+(In fact, some versions of Fortran would require the
+variables to be in COMMON).
+Thus it is easy to write a linear congruent random number generator
+in Fortran, merely by keeping the seed as a variable in the function.
+It is much more risky to do so in Lisp, since any special variable you
+picked, might be used by some other function.
+Fclosures are an attempt to provide most of the same functionality as
+closures in Lisp Machine Lisp, to users of
+.Fr .
+Fclosures are related to closures in this way:
+.br
+(fclosure '(a b) 'foo) <==>
+.br
+       (let ((a a) (b b)) (closure '(a b) 'foo))
+.sh 3 an\ example
+.sp 1v
+.in 0
+.nf
+.sz -2
+.hl
+% \fBlisp\fP
+Franz Lisp, Opus 38.60
+\->\fB(defun code (me count)
+  (print (list 'in x))
+  (setq x (+ 1 x))
+  (cond ((greaterp count 1) (funcall me me (sub1 count))))
+  (print (list 'out x)))\fP
+code
+\->\fB(defun tester (object count)
+  (funcall object object count) (terpri))\fP
+tester
+\->\fB(setq x 0)\fP
+0
+\->\fB(setq z (fclosure '(x) 'code))\fP
+fclosure[8]
+\->\fB (tester z 3)\fP
+(in 0)(in 1)(in 2)(out 3)(out 3)(out 3)
+nil
+\->\fBx\fP
+0
+.hl
+.fi
+.sz +2
+.sp 3v
+.pp
+The function \fIfclosure\fP creates a new object
+that we will call an fclosure,
+(although it is actually a vector).
+The fclosure contains a functional object, and a set of symbols and
+values for the symbols.  In the above example, the fclosure functional
+object is the function code.
+The set of symbols and values just contains the symbol `x' and
+zero, the value of `x' when the fclosure was created.
+.lp
+When an fclosure is funcall'ed:
+.ip 1)
+The Lisp system lambda binds the symbols in the fclosure to their values in the fclosure.
+.ip 2)
+It continues the funcall on the functional object of the fclosure.
+.ip 3)
+Finally, it un-lambda binds the symbols in the fclosure and at the
+same time stores the current values of the symbols in the fclosure.
+.sp 1v
+.pp
+Notice that the fclosure is saving the value of the symbol `x'.
+Each time a fclosure is created, new space is allocated for saving
+the values of the symbols. Thus if we execute fclosure again, over
+the same function, we can have two independent counters:
+.sp 1v
+.in 0
+.nf
+.sz -2
+.hl
+\-> \fB(setq zz (fclosure '(x) 'code))\fP
+fclosure[1]
+\-> \fB(tester zz 2)\fP
+(in 0)(in 1)(out 2)(out 2)
+\-> \fB(tester zz 2)\fP
+(in 2)(in 3)(out 4)(out 4)
+\-> \fB(tester z 3)\fP
+(in 3)(in 4)(in 5)(out 6)(out 6)(out 6)
+.hl
+.fi
+.sz +2
+.sp 3v
+.sh 3 useful\ functions
+.pp
+Here are some quick some summaries of functions dealing with closures.
+They are more formally defined in \(sc2.8.4.
+To recap, fclosures are made by
+\fI(fclosure 'l_vars 'g_funcobj)\fP.
+l_vars is a list of symbols (not containing nil),
+g_funcobj is any object that can be funcalled.
+(Objects which can be funcalled, include compiled Lisp functions,
+lambda expressions, symbols, foreign functions, etc.)
+In general, if you want a compiled function to be closed over a
+variable, you must declare the variable to be special within the function.
+Another example would be:
+.(l
+       (fclosure '(a b) #'(lambda (x) (plus x a)))
+.)l
+Here, the #' construction will make the compiler compile the lambda expression.
+.pp
+There are times when you want to share variables between fclosures.
+This can be done if the fclosures are created at the same time using
+\fIfclosure-list\fP.
+The function \fIfclosure-alist\fP returns an assoc list giving
+the symbols and values in the fclosure.  The predicate
+\fIfclosurep\fP returns t iff its argument is a fclosure.
+Other functions imported from Lisp Machine Lisp are
+.i symeval-in-fclosure,
+.i let-fclosed,
+and
+.i set-in-fclosure.
+Lastly, the function \fIfclosure-function\fP returns the function argument.
+.sh 3 internal\ structure
+.pp
+Currently, closures are implemented as vectors, with property being the
+symbol fclosure.  The functional object is the first entry.
+The remaining entries are structures which point to the symbols
+and values for the closure, (with a reference count to determine
+if a recursive closure is active).
+.sh 2 foreign\ subroutines\ and\ functions
+.pp
+.Fr 
+has the ability to dynamically load object files produced by other compilers
+and to call functions defined in those files.
+These functions are called 
+.i foreign
+functions.*
+.(f
+*This topic is also discussed in Report PAM-124 of the Center for
+Pure and Applied Mathematics, UCB, entitled ``Parlez-Vous Franz?
+An Informal Introduction to Interfacing Foreign Functions to Franz LISP'',
+by James R. Larus
+.)f
+There are seven types of foreign functions.
+They are characterized by
+the type of result they return, and by differences in the interpretation
+of their arguments.
+They come from two families: a group suited for languages which pass
+arguments by reference (e.g. Fortran), and a group suited for languages
+which pass arguments by value (e.g. C).
+.sp 1v
+.lp
+There are four types in the first group:
+.ip \fBsubroutine\fP
+This does not return anything. 
+The Lisp system
+always returns t after calling a subroutine.
+.ip \fBfunction\fP
+This returns whatever the function returns.
+This must be a valid Lisp object or it may cause the Lisp system to fail.
+.ip \fBinteger-function\fP
+This returns an integer which the Lisp system makes into a fixnum and returns.
+.ip \fBreal-function\fP
+This returns a double precision real number which the Lisp
+system makes into a flonum and returns.
+.sp 1v
+.lp
+There are three types in the second group:
+.ip \fBc-function\fP
+This is like an integer function, except for its different interpretation
+of arguments.
+.ip \fBdouble-c-function\fP
+This is like a real-function.
+.ip \fBvector-c-function\fP
+This is for C functions which return a structure.
+The first argument to such functions must be a vector (of type vectori),
+into which the result is stored.
+The second Lisp argument
+becomes the first argument to the C function, and so on
+.lp
+A foreign function is accessed through a binary object just like a 
+compiled Lisp function.
+The difference is that the discipline field of a binary object
+for a foreign function is a string 
+whose first character is given in the following table:
+.sp 1v
+.TS
+box center ;
+c | c .
+letter type
+=
+s      subroutine
+_
+f      function
+_
+i      integer-function
+_
+r      real-function.
+_
+c      c-function
+_
+v      vector-c-function
+_
+d      double-c-function
+_
+.TE
+Two functions are provided for setting-up foreign functions.
+.i Cfasl
+loads an object file into the Lisp system and sets up one foreign
+function binary object.
+If there are more than one function in an object file, 
+.i getaddress
+can be used to set up additional foreign function objects.
+.pp
+Foreign  functions are called just like other functions, e.g 
+\fI(funname\ arg1\ arg2)\fP.
+When a function in the Fortran group is called,
+the arguments are evaluated and then examined.
+List, hunk and symbol arguments are passed unchanged to 
+the foreign function.
+Fixnum and flonum arguments are copied into a temporary location and
+a pointer to the value is passed (this is because Fortran uses call
+by reference and it is dangerous to modify the contents of a fixnum
+or flonum which something else might point to).
+If the argument is an array object,
+the data field of the array object is
+passed to the foreign function
+(This is the easiest way to send large
+amounts of data to and receive large amounts of data from a foreign
+function).
+If a binary object is an argument, the entry field of that object is
+passed to the foreign function (the entry field is the address of a function,
+so this amounts to passing a function as an argument).
+.pp
+When a function in the C group is called,
+fixnum and flownum arguments are passed by value.
+For almost all other arguments,
+the address is merely provided to the C routine.
+The only exception arises when you want to invoke a C routine
+which expects a ``structure'' argument.  Recall that a (rarely used)
+feature of the C language is the ability to pass structures by value.
+This copies the structure onto the stack.  Since the Franz's nearest
+equivalent to a C structure is a vector, we provide an escape clause
+to copy the contents of an immediate-type vector by value.  If the
+property field of a vectori argument, is the symbol
+\*(lqvalue-structure-argument\*(rq,
+then the binary data of this immediate-type vector is copied
+into the argument list of the C routine.
+.pp
+The method a foreign function uses to access the arguments provided 
+by Lisp is dependent on the language of the foreign function.
+The following scripts demonstrate how how Lisp can interact with three
+languages: C, Pascal and Fortran.
+C and Pascal have pointer types and the first script shows how to use
+pointers to extract information from Lisp objects.
+There are two functions defined for each language.
+The first (cfoo in C, pfoo in Pascal) is given four arguments, a 
+fixnum, a flonum-block array, a hunk of at least two
+fixnums and a list of 
+at least two fixnums.
+To demonstrate that the values were passed, each ?foo function prints
+its arguments (or parts of them).
+The ?foo function then modifies the second element of 
+the flonum-block array and returns a 3 to Lisp.
+The second function (cmemq in C, pmemq in Pascal) acts just like the
+Lisp
+.i memq
+function (except it won't work for fixnums whereas the lisp 
+.i memq
+will work for small fixnums).
+In the script, typed input is in 
+.b bold ,
+computer output is in roman
+and comments are in
+.i italic.
+.in 0
+.nf
+.sp 2v
+.sz -2
+.hl
+\fIThese are the C coded functions  \fP
+% \fBcat ch8auxc.c\fP
+/* demonstration of c coded foreign integer-function */
+
+/* the following will be used to extract fixnums out of a list of fixnums */
+struct listoffixnumscell
+{    struct listoffixnumscell *cdr;
+     int *fixnum;
+};
+
+struct listcell
+{      struct listcell *cdr;
+       int car;
+};
+
+cfoo(a,b,c,d)
+int *a;
+double b[];
+int *c[];
+struct listoffixnumscell *d;
+{
+    printf("a: %d, b[0]: %f, b[1]: %f\n", *a, b[0], b[1]);
+    printf(" c (first): %d   c (second): %d\n",
+              *c[0],*c[1]);
+    printf(" ( %d %d ... )\n ", *(d->fixnum), *(d->cdr->fixnum));
+    b[1] = 3.1415926;
+    return(3);
+}
+
+struct listcell *
+cmemq(element,list)
+int element;
+struct listcell *list;
+{   
+   for( ; list && element != list->car ;  list = list->cdr);
+   return(list);
+}
+.sp 2v
+\fIThese are the Pascal coded functions \fP
+% \fBcat ch8auxp.p\fP
+type   pinteger = ^integer;
+       realarray = array[0..10] of real;
+       pintarray = array[0..10] of pinteger;
+       listoffixnumscell = record  
+                               cdr  : ^listoffixnumscell;
+                               fixnum : pinteger;
+                           end;
+       plistcell = ^listcell;
+       listcell = record
+                     cdr : plistcell;
+                     car : integer;
+                  end;
+
+function pfoo ( var a : integer ; 
+               var b : realarray;
+               var c : pintarray;
+               var d : listoffixnumscell) : integer;
+begin
+   writeln(' a:',a, ' b[0]:', b[0], ' b[1]:', b[1]);
+   writeln(' c (first):', c[0]^,' c (second):', c[1]^);
+   writeln(' ( ', d.fixnum^, d.cdr^.fixnum^, ' ...) ');
+   b[1] := 3.1415926;
+   pfoo := 3
+end ;
+
+{ the function pmemq looks for the Lisp pointer given as the first argument
+  in the list pointed to by the second argument.
+  Note that we declare " a : integer " instead of " var a : integer " since
+  we are interested in the pointer value instead of what it points to (which
+  could be any Lisp object)
+}
+function pmemq( a : integer; list : plistcell) : plistcell;
+begin
+ while (list <> nil) and (list^.car <> a) do list := list^.cdr;
+ pmemq := list;
+end ;
+.sp 2v
+\fIThe files are compiled\fP
+% \fBcc -c ch8auxc.c\fP
+1.0u 1.2s 0:15 14% 30+39k 33+20io 147pf+0w
+% \fBpc -c ch8auxp.p\fP
+3.0u 1.7s 0:37 12% 27+32k 53+32io 143pf+0w
+.sp 2v
+% \fBlisp\fP
+Franz Lisp, Opus 38.60
+.ft I
+.fi
+First the files are loaded and we set up one foreign function binary.
+We have two functions in each file so we must choose one to tell cfasl about.
+The choice is arbitrary.
+.ft P
+.br 
+.nf
+\->\fB (cfasl 'ch8auxc.o '_cfoo 'cfoo "integer-function")\fP
+/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxc.o -e _cfoo -o /tmp/Li7055.0  -lc
+#63000-"integer-function"
+\->\fB (cfasl 'ch8auxp.o '_pfoo 'pfoo "integer-function" "-lpc")\fP
+/usr/lib/lisp/nld -N -A /tmp/Li7055.0 -T 63200 ch8auxp.o -e _pfoo -o /tmp/Li7055.1 -lpc -lc
+#63200-"integer-function"
+.ft I
+Here we set up the other foreign function binary objects
+.ft P
+\->\fB (getaddress '_cmemq 'cmemq "function" '_pmemq 'pmemq "function")\fP
+#6306c-"function"
+.ft I
+.fi
+We want to create and initialize an array to pass to the cfoo function.
+In this case we create an unnamed array and store it in the value cell of
+testarr. 
+When we create an array to pass to the Pascal program we will use a named
+array just to demonstrate the different way that named and unnamed arrays
+are created and accessed.
+.br
+.nf
+.ft P
+\->\fB (setq testarr (array nil flonum-block 2))\fP
+array[2]
+\->\fB (store (funcall testarr 0) 1.234)\fP
+1.234
+\->\fB (store (funcall testarr 1) 5.678)\fP
+5.678
+\->\fB (cfoo 385 testarr (hunk 10 11 13 14) '(15 16 17))\fP
+a: 385, b[0]: 1.234000, b[1]: 5.678000
+ c (first): 10   c (second): 11
+ ( 15 16 ... )
+ 3
+.ft I
+.fi
+Note that cfoo has returned 3 as it should.
+It also had the side effect of changing the second value of the array to
+3.1415926  which check next.
+.br
+.nf
+.ft P
+\->\fB (funcall testarr 1)\fP
+3.1415926
+.sp 2v
+.fi
+.ft I
+In preparation for calling pfoo we create an array.
+.ft P
+.nf
+\->\fB (array test flonum-block 2)\fP
+array[2]
+\->\fB (store (test 0) 1.234)\fP
+1.234
+\->\fB (store (test 1) 5.678)\fP
+5.678
+\->\fB (pfoo 385 (getd 'test) (hunk 10 11 13 14) '(15 16 17))\fP
+ a:       385 b[0]:  1.23400000000000E+00 b[1]:  5.67800000000000E+00
+ c (first):        10 c (second):        11
+ (         15        16 ...) 
+3
+\->\fB (test 1)\fP
+3.1415926
+.sp 1v
+\fI Now to test out the memq's
+\-> \fB(cmemq 'a '(b c a d e f))\fP
+(a d e f)
+\-> \fB(pmemq 'e '(a d f g a x))\fP
+nil
+.hl
+.fi
+.sz +2
+.sp 3v
+.pp
+The Fortran example will be much shorter since in Fortran 
+you can't follow pointers
+as you can in other languages.
+The Fortran function ffoo is given three arguments: a fixnum, a 
+fixnum-block array and a flonum.
+These arguments are printed out to verify that they made it and
+then the first value of the array is modified.
+The function returns a double precision value which is converted to a flonum
+by lisp and printed.
+Note that the entry point corresponding to the Fortran function ffoo is
+_ffoo_ as opposed to the C and Pascal convention of preceding the name with
+an underscore.
+.sp 1v
+.in 0
+.nf
+.sz -2
+.hl
+
+% \fBcat ch8auxf.f\fP
+       double precision function ffoo(a,b,c)
+       integer a,b(10)
+       double precision c
+       print 2,a,b(1),b(2),c
+2      format(' a=',i4,', b(1)=',i5,', b(2)=',i5,' c=',f6.4)
+       b(1) = 22
+       ffoo = 1.23456
+       return
+       end
+% \fBf77 -c ch8auxf.f\fP
+ch8auxf.f:
+   ffoo:
+0.9u 1.8s 0:12 22% 20+22k 54+48io 158pf+0w
+% \fBlisp\fP
+Franz Lisp, Opus 38.60
+\-> \fB(cfasl 'ch8auxf.o '_ffoo_ 'ffoo "real-function" "-lF77 -lI77")\fP
+/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxf.o -e _ffoo_ 
+-o /tmp/Li11066.0 -lF77 -lI77 -lc
+#6307c-"real-function"
+.sp 1v
+\-> \fB(array test fixnum-block 2)\fP
+array[2]
+\->\fB (store (test 0) 10)\fP
+10
+\-> \fB(store (test 1) 11)\fP
+11
+\-> \fB(ffoo 385 (getd 'test) 5.678)\fP
+ a= 385, b(1)=   10, b(2)=   11 c=5.6780
+1.234559893608093
+\-> \fB(test 0)\fP
+22
+
+.hl
diff --git a/usr/src/include/fcntl.h b/usr/src/include/fcntl.h
new file mode 100644 (file)
index 0000000..3813570
--- /dev/null
@@ -0,0 +1,27 @@
+/*     fcntl.h 4.2     83/09/25        */
+
+/*
+ * Flag values accessible to open(2) and fcntl(2)
+ *  (The first three can only be set by open)
+ */
+#define        O_RDONLY        0
+#define        O_WRONLY        1
+#define        O_RDWR          2
+#define        O_NDELAY        FNDELAY /* Non-blocking I/O */
+#define        O_APPEND        FAPPEND /* append (writes guaranteed at the end) */
+
+#ifndef        F_DUPFD
+/* fcntl(2) requests */
+#define        F_DUPFD 0       /* Duplicate fildes */
+#define        F_GETFD 1       /* Get fildes flags */
+#define        F_SETFD 2       /* Set fildes flags */
+#define        F_GETFL 3       /* Get file flags */
+#define        F_SETFL 4       /* Set file flags */
+#define        F_GETOWN 5      /* Get owner */
+#define F_SETOWN 6     /* Set owner */
+
+/* flags for F_GETFL, F_SETFL-- copied from <sys/file.h> */
+#define        FNDELAY         00004           /* non-blocking reads */
+#define        FAPPEND         00010           /* append on each write */
+#define        FASYNC          00100           /* signal pgrp when data ready */
+#endif
diff --git a/usr/src/ucb/lisp/Makefile b/usr/src/ucb/lisp/Makefile
new file mode 100644 (file)
index 0000000..07bc159
--- /dev/null
@@ -0,0 +1,255 @@
+# $Header: Makefile,v 1.25 83/09/12 16:26:12 sklower Exp $
+#  Makefile for total Franz Lisp system.
+#
+# Read the file ReadMe for directions on how to build the system.
+#
+#    capabilities of this directory.
+# copylibrary: copies distribution copy of lisp directory to LibDir
+# fast: make a new lisp and liszt assuming that a liszt and lisp
+#      already exist.  Results are franz/mylisp and liszt/nliszt.
+#      Use 'make install' to install it.
+# install: moves franz/mylisp to ObjDir/lisp  and moves
+#      liszt/nliszt to ObjDir/liszt
+#
+#-- the rest of the capabilities are for use when making a distribution
+#   directory.
+# copyallsource: copies lisp distrib files in the current directory tree 
+#       to the tree CopyTo.  
+#      CopyTo should exist already, but the subdirectories
+#      need not exist.
+#
+# Before doing one of the below, you should make sure that the on line
+# manual is up to date.  Go to the doc subdirectory and type 
+#      'make rall install'
+#
+# lispdist: makes a new distribution directory in LispDist.
+#      LispDist should already exist.
+#
+# lispscriptdist: make a shell script lisp distribution.  The result is put
+#      in LispDist as a set of text files comprising a shell script.
+#      The files are broken into a nice size for transport over the berknet.
+#      The first thing that lispscriptdist does is to, 
+#              'make prelispscriptdist'
+#      Which insures that the files are ready to go.
+#      Also, the value of Version should be set to the version number of
+#      lisp you are making.
+#
+#--- Default paths and programs
+DESTDIR =
+.DEFAULT: all
+
+# the following line is modifed by './lispconf', don't modify it by hand.
+#ifdef vax
+Mach = vax
+#else
+#Mach = 68k
+#endif
+
+RootDir = /usr/src/ucb/lisp
+#ifdef ucbstd
+LibDir = ${DESTDIR}/usr/lib/lisp
+ObjDir = ${DESTDIR}/usr/ucb
+#else
+#LibDir = ${DESTDIR}${RootDir}/lisplib
+#ObjDir = ${DESTDIR}${RootDir}/bin
+#endif
+LispDist = /usr/src/ucb/lispdist
+CopyTo = /dev/null
+Lisp = ${ObjDir}/lisp
+Liszt = ${ObjDir}/liszt
+Version = 38.79
+
+# definitions that you shouldn't change
+FranzD = franz/${Mach}
+LisztD = liszt/${Mach}
+CcodeDir = ../../${FranzD}
+
+#--- this directory also has some sources
+Src = Makefile ReadMe lispconf lispnews scriptcat Notice cvt.awk
+
+#make as lisp and lisp assuming that there are .s files in the
+#lisplib and liszt subdirs
+fromasm:
+#ifdef unisoft
+#      (cd as68 ; make DESTDIR=${LibDir} install)
+#endif
+       (cd utils     ; make LibDir=${LibDir} all)
+       (cd ${LibDir} ; make LibDir=${LibDir} as nld fromasm)
+       (cd ${FranzD} ; make LibDir=${LibDir} ObjDir=${ObjDir} nlisp)
+       (cd ${LisztD} ; make Lisp=${CcodeDir}/nlisp fromasm)
+       (cd liszt     ; make Liszt=${Mach}/nliszt lxref)
+
+## when the lisp system is rebuilt as part of the entire Nbsd distribution,
+# three calls are made: 
+#   first   'make'                     to build lisp,liszt and lxref
+#   next    'make DESTDIR=xxx install' to install the new lisp
+#   finally 'make clean'               to clean out objects
+#
+# the 'make all' is done when just a 'make' is done
+all:
+       (cd utils     ; make LibDir=${LibDir} all)
+       (cd ${LibDir} ; make as nld)
+       (cd ${FranzD} ; make LibDir=${LibDir} ObjDir=${ObjDir} donlisp)
+       (cd ${LisztD} ; make Lisp=${CcodeDir}/nlisp nliszt)
+       (cd liszt     ; make Liszt=${Mach}/nliszt lxref)
+
+       
+copylibrary: 
+#ifdef ucbstd
+       (cd lisplib ; make CopyTo=${LibDir} copysource)
+       -mkdir ${LibDir}/manual
+       (cd doc; make LibDir=${LibDir} FromDir=../lisplib \
+                               CopyTo=${LibDir}/manual copymanual)
+#endif
+
+fast:
+       date
+       (cd utils ; make LibDir=${LibDir} all)
+       (cd ${LibDir}; make as nld tackon)
+       (cd ${FranzD}; make Lisp=${Lisp} Liszt=${Liszt} LibDir=${LibDir}\
+                               ObjDir=${ObjDir} donlisp)
+       (cd ${LisztD}; make Lisp=${CcodeDir}/nlisp Liszt=${Liszt} donliszt)
+       (X=`pwd` ; cd ${LibDir}; make Liszt=$$X/${LisztD}/nliszt clean all)
+       date
+       (cd ${FranzD}; make Liszt=../../${LisztD}/nliszt \
+                       ObjDir=${ObjDir} LibDir=${LibDir} donlisp)
+       date
+       (cd ${LisztD}; make Lisp=${CcodeDir}/nlisp \
+                           Liszt=./nliszt cleanobj nliszt)
+       (cd liszt ; make Liszt=${Mach}/nliszt lxref)
+       date
+
+slow:
+       date
+       (cd utils ; make LibDir=${LibDir} all)
+       (cd ${LibDir}; make as nld)
+       (cd ${FranzD}; make LibDir=${LibDir} ObjDir=${ObjDir} snlisp)
+       date
+       (cd ${LisztD}; make Lisp=${CcodeDir}/snlisp snliszt)
+       (cd ${LisztD}; make Lisp=${CcodeDir}/snlisp Liszt=./snliszt nliszt)
+       rm -f ${LisztD}/snliszt
+       date
+       rm -f ${FranzD}/snlisp
+       (X=`pwd`; cd ${FranzD};make Liszt=$$X/${LisztD}/nliszt \
+                                   ObjDir=${ObjDir}\
+                                   LibDir=${LibDir} nlisp)
+       (cd ${LisztD}; make Lisp=${CcodeDir}/nlisp Liszt=./nliszt nliszt)
+       (X=`pwd`; cd ${LibDir} ; make Liszt=$$X/${LisztD}/nliszt all)
+       (X=`pwd`; cd ${LibDir} ; make Liszt=$$X/${LisztD}/nliszt struct-again)
+       (X=`pwd`; cd ${FranzD} ;  make Liszt=$$X/${LisztD}/nliszt \
+                                      ObjDir=${ObjDir}\
+                                      LibDir=${LibDir} donlisp)
+       (cd ${LisztD}; make Lisp=${CcodeDir}/nlisp Liszt=./nliszt nliszt)
+       (cd liszt ; make Liszt=${Mach}/nliszt lxref)
+       date
+
+install:
+       (cd ${FranzD}; make ObjDir=${ObjDir} LibDir=${LibDir} install)
+       (cd ${LisztD}; make ObjDir=${ObjDir} LibDir=${LibDir} install)
+       (cd liszt; make ObjDir=${ObjDir} LibDir=${LibDir} install)
+
+
+copyallsource:
+       -mkdir ${CopyTo}/franz
+       -mkdir ${CopyTo}/franz/vax
+       -mkdir ${CopyTo}/franz/68k
+       -mkdir ${CopyTo}/liszt
+       -mkdir ${CopyTo}/liszt/vax
+       -mkdir ${CopyTo}/liszt/68k
+       -mkdir ${CopyTo}/doc
+       -mkdir ${CopyTo}/utils
+       -mkdir ${CopyTo}/lisplib
+       -mkdir ${CopyTo}/lisplib/manual
+       -mkdir ${CopyTo}/lisplib/autorun
+       -mkdir ${CopyTo}/pearl
+       cp ${Src} ${CopyTo}
+       (cd franz; make   CopyTo=${CopyTo}/franz copysource)
+       (cd franz/vax; make   CopyTo=${CopyTo}/franz/vax copysource)
+       (cd franz/68k; make   CopyTo=${CopyTo}/franz/68k copysource)
+       (cd liszt; make  CopyTo=${CopyTo}/liszt copysource)
+       (cd liszt/vax; make  CopyTo=${CopyTo}/liszt/vax copysource)
+       (cd liszt/68k; make  CopyTo=${CopyTo}/liszt/68k copysource)
+       (cd ${LibDir} ; make  CopyTo=${CopyTo}/lisplib copysource)
+       (cd doc; make CopyTo=${CopyTo}/doc copysource)
+       (cd utils; make CopyTo=${CopyTo}/utils copysource)
+       (cd doc; \
+          make FromDir=${LibDir} CopyTo=${CopyTo}/lisplib/manual copymanual)
+       (cd pearl; make CopyTo=${CopyTo}/pearl copysource)
+  
+lispdist:
+       (cd ${LispDist}; rm -f -r *)
+       make CopyTo=${LispDist} copyallsource
+
+copyallobjects:
+       (cd franz/vax; make   CopyTo=${CopyTo}/franz/vax copyobjects)
+       (cd franz/68k; make   CopyTo=${CopyTo}/franz/68k copyobjects)
+       (cd liszt/vax; make  CopyTo=${CopyTo}/liszt/vax copyobjects)
+       (cd ${LibDir} ; make  CopyTo=${CopyTo}/lisplib copyobjects)
+
+prelispscriptdist:
+       (cd doc ; make all)
+
+lispscriptdist:
+       (cd ${LispDist}; rm -f -r opus*)
+       make prelispscriptdist
+       (make genlispscript | (cd ${LispDist} ; \
+                              divide -500000 -popus${Version}. -l))
+
+xtra: 
+       (cd ${LispDist}; rm -f -r x${Mach}*)
+       make Mach=${Mach} setupx
+       (make Mach=${Mach} genxtra) | \
+            (cd ${LispDist} ; divide -500000 -px${Mach}.${Version}. -l)
+
+lispas:
+       make genas68 > ${LispDist}/lispas
+
+setupx:
+       (X=`pwd`; cd ${LibDir};\
+       make Liszt="$$X/liszt/${Mach}/nliszt -e '(sstatus feature for-${Mach})'" xtra)
+       (cd liszt/${Mach}; make  -f Makefile2 xtra)
+
+genlispscript:
+       @echo \# Franz Lisp distribution Opus ${Version}
+       @echo mkdir franz
+       @echo mkdir franz/h
+       @echo mkdir franz/vax
+       @echo mkdir franz/68k
+       @echo mkdir liszt
+       @echo mkdir liszt/vax
+       @echo mkdir liszt/68k
+       @echo mkdir doc
+       @echo mkdir utils
+       @echo mkdir pearl
+       @echo mkdir lisplib
+       @echo mkdir lisplib/manual
+       @echo mkdir lisplib/autorun
+       @scriptcat . . ${Src}
+       @echo chmod 775 lispconf
+       @(cd franz ; make scriptcatall)
+       @(cd franz/vax ; make scriptcatall)
+       @(cd franz/68k ; make scriptcatall)
+       @(cd liszt ; make scriptcatall)
+       @(cd liszt/vax ; make scriptcatall)
+       @(cd liszt/68k ; make scriptcatall)
+       @(cd doc ; make LibDir=${LibDir} scriptcatall)
+       @(cd utils ; make scriptcatall )
+       @(X=`pwd` ; cd pearl ; make CdTo=$$X scriptcatall)
+       @(X=`pwd` ; cd ${LibDir} ;  make CdTo=$$X scriptcatall)
+       @echo \# end of Franz Lisp Distribution
+
+genas68:
+       @(echo mkdir as68;cd as68; make scriptcat)
+
+genxtra:
+       @(X=`pwd` ; cd ${LibDir} ;  make CdTo=$$X scriptcatxtra)
+       @(cd liszt/${Mach} ; make -f Makefile2 scriptcatxtra)
+
+clean:
+       cd franz    ; make clean
+       cd franz/vax; make clean
+       cd franz/68k; make clean
+       cd liszt    ; make clean
+       cd liszt/vax; make clean
+       cd liszt/68k; make clean
+       cd doc      ; make clean
diff --git a/usr/src/ucb/lisp/franz/68k/Makefile b/usr/src/ucb/lisp/franz/68k/Makefile
new file mode 100644 (file)
index 0000000..37a77cc
--- /dev/null
@@ -0,0 +1,232 @@
+# 
+#$Header: Makefile,v 1.12 83/09/12 15:33:20 layer Exp $
+#
+#$Locker:  $
+#
+#  Franz Lisp C coded kernel 
+#
+#-- Default Paths:
+#  see ../../ReadMe for a explaination of what LibDir and CopyTo mean
+#  D is the directory used for holding intermediate files during 
+#    compilation
+#-- Options:
+#  there is one compile time options which can be set in this file
+#  * do profiling (ala the unix prof(1) command)
+#
+#  The selection of this options is made below
+#  Other options can be selected by editing ../h/config.h or via
+#  ../../lispconf
+#
+LibDir = /a/franz/lisplib
+ObjDir = /usr/ucb
+CopyTo = /dev/null
+Liszt = liszt
+Lisp = lisp
+# if you change this you must recompile rlc.c 
+# (and change the value in ../Makefile)
+#
+HOLE=  2097152 
+
+.DEFAULT: nlisp
+
+MipSrc1= ../low.c ../lowaux.s
+MipSrc2= ../alloc.c ../data.c
+MipSrc3= ../rlc.c
+MipSrc4= ../lisp.c ../eval.c ../eval2.c ../inits.c ../io.c ../error.c \
+        ../sysat.c ../lam1.c ../lam2.c ../lam3.c ../lam4.c ../lam5.c\
+        ../lam6.c  ../lam7.c ../lam8.c ../lam9.c ../lamr.c ../lamp.c \
+        ../fex1.c ../fex2.c ../fex3.c ../fex4.c ../fexr.c\
+        ../fpipe.c \
+        ../subbig.c ../pbignum.c ../divbig.c \
+        ../ffasl.c ../fasl.c \
+        ../trace.c ../evalf.c ../frame.c ../lamgc.c
+
+MipSrc = ${MipSrc1} ${MipSrc2} ${MipSrc3} ${MipSrc4}
+
+MipObj1= ../low.o ../lowaux.o
+MipObj2= ../alloc.o ../data.o
+HoleMipObj2 = ../Salloc.o ../Sdata.o
+HoleMipObj3 = ../rlc.o
+MipObj4= ../lisp.o ../eval.o ../eval2.o ../inits.o ../io.o ../error.o \
+        ../sysat.o ../lam1.o ../lam2.o ../lam3.o ../lam4.o ../lam5.o\
+        ../lam6.o  ../lam7.o ../lam8.o ../lam9.o ../lamr.o ../lamp.o \
+        ../fex1.o ../fex2.o ../fex3.o ../fex4.o ../fexr.o\
+        ../fpipe.o \
+        ../subbig.o ../pbignum.o ../divbig.o \
+        ../ffasl.o ../fasl.o \
+        ../trace.o ../evalf.o ../frame.o ../lamgc.o
+
+
+# The order of loading of certain files is important.
+# low.o must be first and lowaux second.
+# 
+BottomObj = ${MipObj1}
+
+# Different objects are required depending on whether there is to be
+# a hole between text and data space.
+#
+NoHoleObj = /lib/crt0.o ${MipObj2}
+HoleObj   = /lib/hcrt0.o ${HoleMipObj2} ${HoleMipObj3}
+
+M68kASrc = alloca.s callg.s dmlad.s ediv.s emul.s hack.s \
+       qfuncl.c realread.sun.s realread.s
+M68kCSrc = 68k.c adbig.c calqhat.c dodiv.c dsmult.c \
+       exarith.c fixbits.c inewint.c \
+       mlsb.c mulbig.c nargs.c
+M68kSrc = ${M68kCSrc} ${M68kASrc}
+
+M68kObj = 68k.o adbig.o alloca.o callg.o calqhat.o dmlad.o dodiv.o dsmult.o \
+       ediv.o emul.o exarith.o fixbits.o hack.o inewint.o \
+       mlsb.o mulbig.o nargs.o qfuncl.o
+
+AllSrc = $(M68kSrc) Makefile first8.c fixregs.sed
+
+#ifdef unisoft
+#Libs = -ltermcap -lm -lc
+#OsObjs = realread.o
+#CFLAGS = -I../h
+#else
+Libs = -ltermcap -lcore -lm -lc
+OsObjs = realread.sun.o suncore.o
+CFLAGS = -O -I../h
+#endif
+
+# on non-ucb systems it might be more
+# polite to use temporary files rather than pipes
+#
+#ifdef unisoft
+#.SUFFIXES : .c.l.s
+#.s.o:
+#      first8.out < $< > $*.t; as -o $*.o $*.t; rm $*.t
+#else
+.SUFFIXES : .c.l
+#endif
+.c.o :
+#ifdef npinreg
+#      /lib/cpp -I../h $*.c | /lib/xcomp |\
+#      sed -f fixregs.sed > /tmp/x.s; as -o $*.o /tmp/x.s
+#else
+       cc -c $(CFLAGS) $*.c;\
+       mv `basename $*.o` x; mv x $*.o
+#endif
+
+.l.o :
+       liszt $< > #resc
+       @echo liszt $< done
+
+
+../rlc.o: ../rlc.c 
+       cc -c $(CFLAGS) -DHOLE=${HOLE} ../rlc.c 
+       mv rlc.o .. < /dev/null
+
+../Salloc.o: ../alloc.c
+       (echo "# define HOLE"; cat ../alloc.c) > Salloc.c;\
+       make Salloc.o; mv Salloc.o .. < /dev/null ; rm Salloc.c
+       
+../Sdata.o: ../data.c
+       (echo "# define HOLE"; cat ../data.c) > Sdata.c;\
+       make Sdata.o; mv Sdata.o .. < /dev/null  ; rm Sdata.c
+
+#ifdef unisoft
+#../low.o: ../low.c first8.out
+#      cc -S $(CFLAGS) ../low.c;\
+#      sed s/data/text/ < low.s > low.t;\
+#      as -o ../low.o low.t;\
+#      rm low.s low.t
+#
+#qfuncl.o: qfuncl.c first8.out
+#      cc -E $(CFLAGS) ${ProfFlag2} qfuncl.c |\
+#      first8.out | sed 's/^#/|/' > qfuncl.s
+#      as -o qfuncl.o qfuncl.s
+#      rm qfuncl.s
+#
+#else
+../low.o: ../low.c
+       cc -c $(CFLAGS) -R ../low.c  
+       mv low.o .. < /dev/null
+
+qfuncl.o: qfuncl.c
+       cc -I../h -E ${ProfFlag2} qfuncl.c > x.s; as -o qfuncl.o x.s; rm x.s
+
+suncore.o: suncore.s
+
+suncore.s:
+       nm -pg /usr/lib/libcore.a |\
+       egrep '^0.* T' |\
+       sed 's/.* /.long /' > suncore.s
+
+#endif
+
+# rawlisp is the standard raw lisp system.
+
+rawlisp: ${BottomObj} ${NoHoleObj} ${MipObj4} ${M68kObj} ${OsObjs}
+       rm -f rawlisp
+       ld -n -x -o rawlisp -e start ${BottomObj} ${NoHoleObj} \
+                               ${M68kObj} ${MipObj4} ${OsObjs} ${Libs}
+       ls -l rawlisp
+
+
+# hlisp is a raw lisp system with a hole between text and data
+
+rawhlisp: ${BottomObj} ${HoleObj} ${MipObj4} ${M68kObj} ${OsObjs}
+       rm -f rawhlisp
+       ld -x -H ${HOLE} -o rawhlisp -e hstart ${BottomObj}  ${HoleObj} \
+                               ${M68kObj} ${MipObj4} ${OsObjs} ${Libs}
+       ls -l rawhlisp
+
+
+clean:
+       rm -f *.o rawlisp rawhlisp nlisp snlisp
+
+lint:
+       lint ../h/*.h *.c
+
+install: nlisp 
+       -rm -f ${ObjDir}/lisp
+       mv nlisp ${ObjDir}/lisp
+       @echo lisp installed
+
+nlisp: rawlisp ${LibDir}
+       -rm -f nlisp
+       (cd ${LibDir} ; make Liszt=${Liszt} required)
+       echo "(progn (setq build:map 'map \
+                          build:lisp-type 'franz \
+                          lisp-library-directory '${LibDir} \
+                          build:dir '${LibDir} \
+                          lisp-object-directory '${ObjDir}) \
+                    (load '${LibDir}/buildlisp)\
+                    (dumplisp nlisp))" | ./rawlisp
+       ${LibDir}/tackon map nlisp
+       @echo nlisp built
+
+
+donlisp:
+       -rm -f nlisp
+       make LibDir=${LibDir} Liszt=${Liszt} ObjDir=${ObjDir} nlisp
+
+#--- snlisp: create a totally interpreted lisp.
+#      dump as snlisp
+snlisp: rawlisp
+       echo "(progn (setq build:load t         \
+                          build:lisp-type 'franz \
+                          build:dir '${LibDir} \
+                          lisp-object-directory '${ObjDir}\
+                          lisp-library-directory '${LibDir})\
+                    (load '${LibDir}/buildlisp)\
+                    (dumplisp snlisp))" | rawlisp
+
+
+tags:  tags ${M68kCSrc} ${MipSrc}
+       ctags ../h/*.h $(M68kCSrc) ${MipSrc}
+
+#--- copysource : copy source files to another directory
+#  called via   make CopyTo=/xx/yyy/zz copysource
+# 
+copysource: ${AllSrc}
+       (tar cf - ${AllSrc} | (cd ${CopyTo} ; tar xf -))
+
+copyobjects: ${AllObj}
+       (tar cf - ${AllObj} | (cd ${CopyTo} ; tar xf -))
+
+scriptcatall: ${AllSrc}
+       @../../scriptcat . franz/68k ${AllSrc} tags
diff --git a/usr/src/ucb/lisp/franz/68k/fixregs.sed b/usr/src/ucb/lisp/franz/68k/fixregs.sed
new file mode 100644 (file)
index 0000000..0361cbe
--- /dev/null
@@ -0,0 +1,3 @@
+/_np,/s//a2,/
+/_np$/s//a2/
+/_lbot/s//d3/
diff --git a/usr/src/ucb/lisp/franz/68k/qfuncl.c b/usr/src/ucb/lisp/franz/68k/qfuncl.c
new file mode 100644 (file)
index 0000000..b1686dc
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ *$Header: qfuncl.c,v 1.7 83/09/06 21:49:27 layer Exp $
+ *$Locker:  $
+ *
+ * Copyright (c) 1982, by the Regents, University of California
+ *
+ *                     -[Tue Mar 22 15:42:27 1983 by layer]-
+ *
+ * "quick" functions file.
+ *
+ * This is written in assembler but must be passed through the C preprocessor
+ * before being assembled.
+ *
+ */
+
+#include "ltypes.h"
+#include "config.h"
+/* important offsets within data types for atoms */
+#define Atomfnbnd 8
+
+/*  for arrays */
+#define Arrayaccfun 0
+
+/* register defines */
+#define FIXREG d2
+
+#ifdef NPINREG
+#define _np a2
+#define _lbot d3
+#endif
+
+
+#ifdef PROF
+       .set    indx,0
+#define Profile \
+       lea     prbuf+indx,a0 \
+       .set    indx,indx+4 \
+       jsr     mcount 
+#define Profile2 \
+       movl    a0,sp@-
+       lea     prbuf+indx,a0 \
+       .set    indx,indx+4 \
+       jsr     mcount 
+       movl    sp@+,a0
+#else
+#define Profile
+#define Profile2
+#endif
+
+#ifdef PORTABLE
+#define        NILtest(p)      cmpl    #/**/OFFSET,p
+#define        NILsub(p)       subl    #/**/OFFSET,p
+#else
+#define NILtest(p)
+#define NILsub(p)
+#endif
+
+
+       .text
+       
+/*   transfer  table linkage routine  */
+       .globl  _qlinker
+_qlinker:
+       Profile
+       link    a6,#-28
+       tstb    sp@(-132)
+       moveml  #036000,a6@(-28)                |a(2,3,4,5)
+
+       tstl    _exception                      |any pending exceptions
+       jeq     noexc
+       tstl    _sigintcnt                      |is it because of SIGINT
+       jeq     noexc                           |if not, just leave
+       movl    #2,sp@-                         |else push SIGINT
+       jsr     _sigcall
+noexc:
+       movl    a6@(4),a4                       |get return pc
+       movl    a4@(-6),a4                      |get pointer to table
+       movl    a4@(4),a5                       |get atom pointer
+retry:                                         |come here after undeffunc err
+       movl    a5@(8),a0                       |get function binding
+       cmpl    a0,d7                           |if nil,
+       jeq     nonex                           |then leave
+       tstl    2*4+_stattab                    |see if linkin posble (Strans)
+       jeq     nolink                          |no, it isn't
+       movl    a0,d0                           |check type of function
+       NILsub(d0)
+       moveq   #9,d1
+       asrl    d1,d0
+       lea     _typetable+1,a3
+       movb    a3@(0,d0:L),d1
+       cmpb    #/**/BCD,d1
+       jeq     linkin                          |bcd, link it in!
+       cmpb    #/**/ARRAY,d1                   |how about array?
+       jeq     doarray                         |yep
+
+nolink:
+       movl    a5,sp@-                         |non, bcd, call interpreter
+       jsr     _Ifuncal
+       moveml  a6@(-28),#036000
+       unlk    a6
+       rts
+
+/*
+ * handle arrays by pushing the array descriptor on the table and checking
+ * for a bcd array handler
+ */
+doarray:
+       movl    a0@(Arrayaccfun),d0             |get access func addr shifted
+       NILsub(d0)
+       movl    #9,d1
+       asrl    d1,d0
+       lea     _typetable+1,a3
+       cmpb    #/**/BCD,a3@(0,d0:L)            |bcd??
+       jne     nolink                          |no, let funcal handle it
+       movl    a0,a2@+                         |store array header on stack
+       movl    a2,_np
+       movl    a0@,a0                          |movl *(a0),a0 on VAX
+       movl    a0@,a0
+       jsr     a0@
+       subql   #4,_np
+       moveml  a6@(-28),#036000
+       unlk    a6
+       rts
+       
+       
+linkin:        
+       movl    a0@(4),d0                       |check type of function discipline
+       NILsub(d0)
+       movl    #9,d1
+       asrl    d1,d0
+       lea     _typetable+1,a3
+       cmpb    #/**/STRNG,a3@(0,d0:L)          |is it string?
+       jeq     nolink                          |yes, it is a c call,
+                                               |so dont link in
+       movl    a0@,a0                          |get function addr
+       movl    a0,a4@                          |put fcn addr in table
+       jbsr    a0@
+       moveml  a6@(-28),#036000
+       unlk    a6
+       rts
+
+
+nonex: movl    a4,sp@-                         |preserve table address
+       movl    a5,sp@-                         |non existant fcn
+       jsr     _Undeff                         |call processor
+       movl    d0,a5                           |back in r1
+       addql   #4,sp
+       movl    sp@+,a4                         |restore table address
+       jra     retry                           |for the retry.
+
+
+       .data
+       .globl  __erthrow
+__erthrow: 
+       .asciz  "Uncaught throw from compiled code"
+       .text
+
+       .globl _tynames
+_tynames:
+       .long   _nilatom                        |nothing here
+       .long   20*4+_lispsys                   |str_name
+       .long   21*4+_lispsys                   |atom_name
+       .long   19*4+_lispsys                   |int_name
+       .long   23*4+_lispsys                   |dtpr_name
+       .long   22*4+_lispsys                   |doub_name
+       .long   58*4+_lispsys                   |funct_name
+       .long   103*4+_lispsys                  |port_name
+       .long   47*4+_lispsys                   |array_name
+       .long   _nilatom                        |nothing here
+       .long   50*4+_lispsys                   |sdot_name
+       .long   53*4+_lispsys                   |val_nam
+
+       .long   _nilatom                        | hunk2_nam
+       .long   _nilatom                        | hunk4_nam
+       .long   _nilatom                        | hunk8_nam
+       .long   _nilatom                        | hunk16_nam
+       .long   _nilatom                        | hunk32_nam
+       .long   _nilatom                        | hunk64_nam
+       .long   _nilatom                        | hunk128_nam
+       .long   124*4+_lispsys                  |vector_nam
+       .long   125*4+_lispsys                  |vectori_nam
+
+/*     Quickly allocate small fixnums  */
+
+       .globl  _qnewint
+_qnewint:
+       Profile
+       cmpl    #1024,FIXREG
+       bge     alloc
+       cmpl    #-1024,FIXREG
+       bmi     alloc
+       movl    FIXREG,d0
+       asll    #2,d0
+       addl    #_Fixzero,d0
+       rts
+alloc:
+       movl    _int_str,a0                     |move next cell addr to r0
+       NILtest(a0)
+       jmi     callnewi                        |if no space, allocate
+       movl    4*24+_lispsys,a1
+       addql   #1,a1@                          |inc count of ints
+       movl    a0@,_int_str                    |advance free list
+       movl    FIXREG,a0@                      |put baby to bed.
+       movl    a0,d0
+       rts
+callnewi:
+       movl    FIXREG,sp@-
+       movl    a2,_np                          |gc could occur
+       movl    a2,_lbot
+       jsr     _newint
+       movl    d0,a0
+       movl    sp@+,a0@
+       rts
+
+/*  _qoneplus adds one to the boxed fixnum in r0
+ * and returns a boxed fixnum.
+ */
+
+       .globl  _qoneplus
+_qoneplus:
+       Profile
+       movl    a0@,FIXREG
+       addql   #1,FIXREG
+       bra     _qnewint
+
+/* _qoneminus  subtracts one from the boxes fixnum in r0 and returns a
+ * boxed fixnum
+ */
+       .globl  _qoneminus
+_qoneminus:
+       Profile
+       movl    a0@,FIXREG
+       subql   #1,FIXREG
+       bra     _qnewint
+
+/*
+ *     _qnewdoub quick allocation of a initialized double (float) cell.
+ *     This entry point is required by the compiler for symmetry reasons.
+ *     Passed to _qnewdoub in d0,d1 is a double precision floating point
+ *     number.  This routine allocates a new cell, initializes it with
+ *     the given value and then returns the cell.
+ */
+
+       .globl  _qnewdoub
+    
+_qnewdoub:
+       Profile
+       movl    _doub_str,a0                    |move next cell addr to r0
+       NILtest(a0)
+       jmi     callnewd                        |if no space, allocate
+       |incl   *_lispsys+30*4                  |inc count of doubs
+       lea     30*4+_lispsys,a1
+       addl    #1,a1@
+       movl    a0@,_doub_str                   |advance free list
+strdb:
+       movl    d0,a0@                          |put baby to bed.
+       movl    d1,a0@(4)                       |put baby to bed.
+       rts
+
+callnewd:
+       movl    d0,sp@-                         |stack initial value
+       movl    d1,sp@-                         |stack initial value
+       movl    a2,_np                          |gc could occur
+       movl    a2,_lbot
+       jsr     _newdoub
+       movl    d0,a0
+       movl    sp@+,d1                         |restore initial value
+       movl    sp@+,d0                         |restore initial value
+       bra     strdb
+
+
+
+/*
+ * quick cons call, the car and cdr are stacked on the namestack
+ * and this function is jsb'ed to.
+ */
+       .globl  _qcons
+_qcons:
+       Profile
+       movl    _dtpr_str,a0                    |move next cell addr to a0
+       NILtest(a0)
+       jmi     getnew                          |if ran out of space jump
+       movl    28*4+_lispsys,a1                |inc count of dtprs
+       addql   #1,a1@
+       movl    a0@,_dtpr_str                   |advance free list
+storit:        movl    a2@-,a0@                        |store in cdr
+       movl    a2@-,a0@(4)                     |store in car
+       movl    a0,d0
+       rts
+
+getnew:        movl    a2,_np
+       jsr     _newdot                         |must gc to get one
+       jra     storit                          |now initialize it.
+
+/*
+ * Fast equivalent of newdot, entered by jsb
+ */
+
+       .globl  _qnewdot
+_qnewdot:
+       Profile
+       movl    _dtpr_str,a0                    |mov next cell addr t0 r0
+       NILtest(a0)
+       jmi     mustallo                        |if ran out of space
+
+       movl    a0,sp@-
+       movl    28*4+_lispsys,a0                |inc count of dtprs
+       addql   #1,a0@
+       movl    sp@+,a0
+
+       movl    a0@,_dtpr_str                   |advance free list
+       clrl    a0@                             |clrq (r0)
+       clrl    a0@(4)
+       rts
+mustallo:
+       movl    a2,_np                          |gc could occur
+       jsr     _newdot
+       rts
+
+
+/*
+ * this is called exactly like popnames would be from C
+ * but has been carefully improved so that it doesn't
+ * have to alter the stack.
+ */
+       .globl  _qpopnames
+_qpopnames:
+       movl    _bnp,a1
+       movl    sp,a0
+       movl    a0@(4),d0
+       jra     .L130
+.L20001:
+       movl    a1@(4),a0
+       movl    a1@,a0@
+.L130:
+       subql   #8,a1
+       cmpl    a1,d0
+       jls     .L20001
+       movl    a1,_bnp
+       rts
+
+/*
+ * _qget : fast get subroutine
+ *  (get 'atom 'ind)
+ * called with a2@(-8) equal to the atom
+ *            a2@(-4) equal to the indicator
+ * no assumption is made about _lbot
+ * unfortunately, the atom may not in fact be an atom, it may
+ * be a list or nil, which are special cases.
+ * For nil, we grab the nil property list (stored in a special place)
+ * and for lists we punt and call the C routine since it is  most likely
+ * and error and we havent put in error checks yet.
+ */
+
+       .globl  _qget
+_qget:
+       Profile
+       movl    a2@(-4),a1                      |put indicator in a1
+       movl    a2@(-8),a0                      |and atom into a0
+       cmpl    a0,d7
+       jeq     nilpli                          |jump if atom is nil
+       movl    a0,d0                           |check type
+       NILsub(d0)
+       movl    #9,d1
+       asrl    d1,d0
+       lea     _typetable+1,a5
+       cmpb    #/**/ATOM,a5@(0,d0:L)           |is it a symbol??
+       jne     notsymb                         |nope
+       movl    a0@(4),a0                       |yes, put prop list in
+                                               |       a0 to begin scan
+       cmpl    a0,d7
+       jeq     fail                            |if no prop list,
+                                               |       we lose right away
+lp:    cmpl    a0@(4),a1                       |is car of list = to indicator?
+       jeq     good                            |jump if so
+       movl    a0@,a0                          |else cddr
+       movl    a0@,a0                          |       down list
+       cmpl    a0,d7
+       jne     lp                              |and jump if more list to go.
+
+fail:  movl    a0,d0
+       subql   #8,a2
+       rts                                     |return with a0 eq to nil
+
+good:  movl    a0@,a0                          |return cadr of list
+       movl    a0@(4),d0
+       subql   #8,a2
+       rts
+
+nilpli:        movl    64*4+_lispsys,a0                |want nil prop list,
+                                               |       get it specially
+       cmpl    a0,d7
+       jne     lp                              |and process if anything there
+       movl    a0,d0
+       subql   #8,a2
+       rts                                     |else fail
+       
+notsymb:
+       lea     a2@(-8),a0                      |set up lbot before callin
+       movl    a0,_lbot
+       movl    a2,_np
+       jsr     _Lget                           |not a symbol, call C routine
+                                               |       to error check
+       subql   #8,a2
+       rts                                     |and return what it returned.
+
+
+/*
+ *  prunel  - return a list of dtpr cells to the free list
+ * this is called by the pruneb after it has discarded the top bignum 
+ * the dtpr cells are linked through their cars not their cdrs.
+ * this returns with an rsb
+ *
+ * method of operation: the dtpr list we get is linked by car's so we
+ * go through the list and link it by cdr's, then have the last dtpr
+ * point to the free list and then make the free list begin at the
+ * first dtpr.
+ */
+qprunel:
+       movl    a0,d0                           |remember first dtpr location
+       movl    28*4+_lispsys,a1                |dec count of dtprs
+rep:   
+       subql   #1,a2@
+       movl    a0@(4),a0@                      |make cdr (forward lnk) == car
+       jeq     endoflist                       |if nil, then end of list
+       movl    a0@,a0                          |advance to next dtpr
+       jra     rep                             |and loop around
+endoflist:
+       movl    _dtpr_str,a0@                   |make last 1 pnt to free list
+       movl    d0,_dtpr_str                    |& free list begin at 1st one
+       rts
+
+/*
+ * qpruneb - called by the arithmetic routines to free an sdot and the dtprs
+ * which hang on it.
+ * called by
+ *     pushl   sdotaddr
+ *     jsb     _qpruneb
+ */
+       .globl  _qpruneb
+_qpruneb:
+       Profile
+       movl    48*4+_lispsys,a0                |decr count of used sdots
+       subql   #1,a0@
+       movl    sp@(4),a0                       |get address
+       movl    _sdot_str,a0@                   |have new sdot pnt to free lst
+       movl    a0,_sdot_str                    |strt free list at new sdot
+       movl    a0@(4),a0                       |get address of first dtpr
+       jne     qprunel                         |if exists, prune it
+       rts                                     |else return.
+
+
+/*
+ * _qprunei     
+ *     called by the arithmetic routines to free a fixnum cell
+ * calling sequence
+ *     pushl   fixnumaddr
+ *     jsb     _qprunei
+ */
+
+       .globl  _qprunei
+_qprunei:
+       Profile
+       movl    a1,sp@-
+       movl    sp@(4),a0                       |get address of fixnum
+       cmpl    #4*1023+_Fixzero,a0             |is it a small fixnum
+       jmi     skipit                          |if so, leave
+       movl    24*4+_lispsys,a1                |decr count of used ints
+       subql   #1,a1@
+       movl    _int_str,a0@                    |link the fixnum into the
+                                               |  free list
+       movl    a0,_int_str
+skipit:
+       movl    sp@+,a1
+       rts
+Iclear:
+       clrl    d0
+       rts
+       .text
+       .globl  _Itstbt
+_Itstbt:
+       movl    a5,d1
+       NILsub(d1)
+       lsrl    #2,d1
+       movl    d1,d0
+       andl    #7,d0
+       lsrl    #3,d1
+       lea     _bitmapi,a0
+       bset    d0,a0@(0,d1:L)
+       beq     .L14
+       moveq   #1,d0
+       bra     .L12
+.L14:
+       clrl    d0
+.L12:  rts
+
+/*
+ * this routine returns an assembly language entry pt.
+ * it is put here to match the vax verison.
+ */
+       .globl  _gstart
+       .globl  _proflush
+_gstart:
+       movl    #start,d0
+_proflush:
+       rts
+/*
+ * The definition of mcount must be present even when the C code
+ * isn't being profiled, since lisp code may reference it.
+ */
+.globl _mcount
+#ifdef SunGotItsActTogetherAboutTakingMcountOutOfCrt0 
+.globl mcount
+#endif
+
+_mcount:
+mcount:
+#ifdef PROF
+       movl    a0@,a1
+       jne     incr
+       movl    _countbase,a1
+       jeq     return
+       addql   #8,_countbase
+       movl    sp@,a1@+
+       movl    a1,a0@
+incr:
+       addql   #1,a1@
+return:
+#endif
+       rts
+
+/*
+ * pushframe : stack a frame 
+ * When this is called, the optional arguments and class have already been
+ * pushed on the stack as well as the return address (by virtue of the jsb)
+ * , we push on the rest of the stuff (see h/frame.h)
+ * for a picture of the save frame
+ */
+       .globl  _pushframe
+       .globl  _qpushframe
+       .globl  _Pushframe
+_pushframe:
+_qpushframe:
+_Pushframe:
+       movl    sp@,a0
+       movl    _errp,sp@-
+       movl    _bnp,sp@-
+       movl    _np,sp@-
+       movl    _lbot,sp@-
+       movl    sp,d0           | return addr of lbot on stack
+       subl    #56,sp
+       moveml  #0x7cfc,sp@(12) | save fp,a5-a2,d7-d2
+       clrl    _retval         | set retval to C_INITIAL
+       jmp     a0@             | return through return address
+
+/*
+ * qretfromfr
+ * called with frame to ret to in a5.  The popnames has already been done.
+ * we must restore all registers, and jump to the ret addr. the popping
+ * must be done without reducing the stack pointer since an interrupt
+ * could come in at any time and this frame must remain on the stack.
+ * thus we can't use popr.
+ */
+
+       .globl  _qretfromfr
+
+_qretfromfr:
+       movl    a5,d0                   | return error frame location
+       movl    a5,a0                   | prepare to pop off
+       moveml  a0@(-44),#0x7cfc        | restore registers
+       lea     a0@(-56),sp
+       movl    a0@+,_lbot
+       movl    a0@+,_np
+       movl    a0@(8),a0               | return address
+       jmp     a0@
+
+/* This must be at the end of the file.  If we are profiling, allocate
+ * space for the profile buffer
+ */
+#ifdef PROF
+       .data
+       .comm   _countbase,4
+       .lcomm  prbuf,indx+4
+       .text
+#endif
diff --git a/usr/src/ucb/lisp/franz/alloc.c b/usr/src/ucb/lisp/franz/alloc.c
new file mode 100644 (file)
index 0000000..689809d
--- /dev/null
@@ -0,0 +1,1576 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: /na/franz/franz/RCS/alloc.c,v 1.8 83/08/06 08:38:19 jkf Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:44:01 1983 by jkf]-
+ *     alloc.c                         $Locker:  $
+ * storage allocator and garbage collector
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+# include "global.h"
+# include "structs.h"
+
+#include <sys/types.h>
+#include <sys/times.h>
+#ifdef METER
+#include <sys/vtimes.h>
+#endif
+# define NUMWORDS TTSIZE * 128  /*  max number of words in P0 space  */
+# define BITQUADS TTSIZE * 2   /*  length of bit map in quad words  */
+# define BITLONGS TTSIZE * 4   /*  length of bit map in long words  */
+
+# ifdef vax
+# define ftstbit       asm("   ashl    $-2,r11,r3");\
+                       asm("   bbcs    r3,_bitmapi,1f");\
+                       asm("   ret"); \
+                       asm("1:");
+
+/* setbit is a fast way of setting a bit, it is like ftstbit except it
+ * always continues on to the next instruction
+ */
+# define setbit                asm("   ashl    $-2,r11,r0"); \
+                       asm("   bbcs    r0,_bitmapi,$0");
+# endif
+
+# if m_68k
+# define ftstbit {if(Itstbt()) return;}
+# define setbit Itstbt()
+# endif
+
+/*  define ftstbit     if( readbit(p) ) return; oksetbit;  */
+# define readbit(p)    ((int)bitmap[r=(int)p>>5] & (s=bitmsk[((int)p>>2)&7]))
+# define lookbit(p)    (bitmap[(int)p>>5] & bitmsk[((int)p>>2) & 7])
+/* # define setbit(p)  {bitmap[(int)p>>5] |= bitmsk[((int)p >> 2) & 7];} */
+# define oksetbit      {bitmap[r] |= s;}
+
+# define readchk(p)    ((int)bitfre[(int)p>>5] & bitmsk[((int)p>>2)&7])
+# define setchk(p)     {bitfre[(int)p>>5] |= bitmsk[((int)p >> 2) & 7];}
+# define roundup(x,l)  (((x - 1) | (l - 1)) + 1) 
+
+# define MARKVAL(v)    if(((int)v) >= (int)beginsweep) markdp(v);
+# define ATOLX(p)      ((((int)p)-OFFSET)>>7)
+
+/* the Vax hardware only allows 2^16-1 bytes to be accessed with one
+ * movc5 instruction.  We use the movc5 instruction to clear the 
+ * bitmaps.
+ */
+# define MAXCLEAR ((1<<16)-1)
+
+/* METER denotes something added to help meter storage allocation. */
+
+extern int *beginsweep;                        /* first sweepable data         */
+extern char purepage[];
+extern int fakettsize;
+extern int gcstrings;
+int debugin  = FALSE;  /* temp debug flag */
+
+extern lispval datalim;                        /*  end of data space */
+int bitmapi[BITLONGS];                 /*  the bit map--one bit per long  */
+double zeroq;                          /*  a quad word of zeros  */
+char *bitmap = (char *) bitmapi;       /*  byte version of bit map array */
+double  *bitmapq = (double *) bitmapi; /*  integer version of bit map array */
+#ifdef METER
+extern int gcstat;
+extern struct vtimes
+       premark,presweep,alldone;       /* actually struct tbuffer's */
+
+extern int markdpcount;
+extern int conssame, consdiff,consnil; /* count of cells whose cdr point
+                                        * to the same page and different
+                                        * pages respectively
+                                        */
+#endif
+char bitmsk[8]={1,2,4,8,16,32,64,128};  /*  used by bit-marking macros  */
+extern int  *bind_lists ;              /*  lisp data for compiled code */
+
+char *xsbrk();
+char *gethspace();
+
+
+extern struct types atom_str, strng_str, int_str, dtpr_str, doub_str,
+       array_str, sdot_str, val_str, funct_str, hunk_str[], vect_str,
+       vecti_str, other_str;
+
+extern struct str_x str_current[];
+
+lispval hunk_items[7], hunk_pages[7], hunk_name[7];
+
+extern int initflag; /* starts off TRUE: initially gc not allowed */
+
+
+/* this is a table of pointers to all struct types objects
+ * the index is the type number.
+ */
+static struct types *spaces[NUMSPACES] = 
+       {&strng_str, &atom_str, &int_str,
+        &dtpr_str, &doub_str, &funct_str, 
+        (struct types *) 0,  /* port objects not allocated in this way  */
+        &array_str,
+        &other_str,  /* other objects not allocated in this way  */
+        &sdot_str,&val_str, 
+        &hunk_str[0], &hunk_str[1], &hunk_str[2],
+        &hunk_str[3], &hunk_str[4], &hunk_str[5],
+        &hunk_str[6],
+        &vect_str, &vecti_str};
+
+
+/* this is a table of pointers to collectable struct types objects
+ * the index is the type number.
+ */
+struct types *gcableptr[] = {
+#ifndef GCSTRINGS
+     (struct types *) 0,  /* strings not collectable */
+#else
+     &strng_str,
+#endif
+     &atom_str,
+     &int_str, &dtpr_str, &doub_str,
+     (struct types *) 0,  /* binary objects not collectable */
+     (struct types *) 0,  /* port objects not collectable */
+     &array_str,
+     (struct types *) 0,  /* gap in the type number sequence */
+     &sdot_str,&val_str, 
+     &hunk_str[0], &hunk_str[1], &hunk_str[2],
+     &hunk_str[3], &hunk_str[4], &hunk_str[5],
+     &hunk_str[6],
+     &vect_str, &vecti_str};
+
+
+/*
+ *   get_more_space(type_struct,purep) 
+ *                                                                     
+ *  Allocates and structures a new page, returning 0.
+ *  If no space is available, returns positive number.
+ *  If purep is TRUE, then pure space is allocated.
+ */
+get_more_space(type_struct,purep)                                 
+struct types *type_struct;
+{
+       int cntr;
+       char *start;
+       int *loop, *temp;
+       lispval p;
+       extern char holend[];
+
+       if( (int) datalim >= TTSIZE*LBPG+OFFSET ) return(2);
+
+       /*
+        * If the hole is defined, then we allocate binary objects
+        * and strings in the hole.  However we don't put strings in
+        * the hole if strings are gc'ed.
+        */
+#ifdef HOLE
+       if(   purep
+#ifndef GCSTRINGS
+          || type_struct==&strng_str
+#endif
+          || type_struct==&funct_str)
+               start = gethspace(LBPG,type_struct->type);
+       else
+#endif
+               start = xsbrk(1);               /* get new page */
+
+
+       SETTYPE(start, type_struct->type,20);  /*  set type of page  */
+
+       purepage[ATOX(start)] = (char)purep;  /* remember if page was pure*/
+
+       /* bump the page counter for this space if not pure */
+
+       if(!purep) ++((*(type_struct->pages))->i);
+
+       type_struct->space_left = type_struct->space;
+       temp = loop = (int *) start;
+       for(cntr=1; cntr < type_struct->space; cntr++)
+               loop = (int *) (*loop = (int) (loop + type_struct->type_len));
+
+       /* attach new cells to either the pure space free list  or the 
+        * standard free list
+        */
+       if(purep) {
+           *loop = (int) (type_struct->next_pure_free);
+           type_struct->next_pure_free = (char *) temp;
+       }
+       else  {
+           *loop = (int) (type_struct->next_free);
+           type_struct->next_free = (char *) temp;
+       }
+
+       /*  if type atom, set pnames to CNIL  */
+
+       if( type_struct == &atom_str )
+               for(cntr=0, p=(lispval) temp; cntr<atom_str.space; ++cntr)
+                       {
+                       p->a.pname = (char *) CNIL;
+                       p = (lispval) ((int *)p + atom_str.type_len);
+                       }
+       return(0);  /*  space was available  */
+}
+
+
+/*
+ * next_one(type_struct) 
+ *
+ *  Allocates one new item of each kind of space, except STRNG.        
+ *  If there is no space, calls gc, the garbage collector.
+ *  If there is still no space, allocates a new page using
+ *  get_more_space
+ */
+
+lispval
+next_one(type_struct)
+struct types *type_struct;
+{
+
+       register char *temp;
+
+       while(type_struct->next_free == (char *) CNIL)
+               {
+               int g;
+
+               if(
+                  (initflag == FALSE) &&       /* dont gc during init */
+#ifndef GCSTRINGS
+                  (type_struct->type != STRNG) && /* can't collect strings */
+#else
+                  gcstrings &&                 /* user (sstatus gcstrings) */
+#endif
+                  (type_struct->type != BCD) &&   /* nor function headers  */
+                  gcdis->a.clb == nil )                /* gc not disabled */
+                                       /* not to collect during load */
+
+                       {
+                       gc(type_struct);  /*  collect  */
+                       }
+
+               if( type_struct->next_free != (char *) CNIL ) break;
+
+               if(! (g=get_more_space(type_struct,FALSE))) break;
+
+               space_warn(g);
+               }
+       temp = type_struct->next_free;
+       type_struct->next_free = * (char **)(type_struct->next_free);
+       (*(type_struct->items))->i ++;
+       return((lispval) temp);
+}
+/*
+ * Warn about exhaustion of space,
+ * shared with next_pure_free().
+ */
+space_warn(g)
+{
+       if( g==1 ) {
+           plimit->i += NUMSPACES; /*  allow a few more pages  */
+           copval(plima,plimit);       /*  restore to reserved reg  */
+
+           error("PAGE LIMIT EXCEEDED--EMERGENCY PAGES ALLOCATED", TRUE);
+       } else error("SORRY, ABSOLUTE PAGE LIMIT HAS BEEN REACHED", TRUE);
+}
+
+
+/* allocate an element of a pure structure.  Pure structures will
+ * be ignored by the garbage collector.
+ */
+lispval
+next_pure_one(type_struct)
+struct types *type_struct;
+{
+
+       register char *temp;
+
+       while(type_struct->next_pure_free == (char *) CNIL)
+               {
+               int g;
+               if(! (g=get_more_space(type_struct,TRUE))) break;
+               space_warn(g);
+               }
+
+       temp = type_struct->next_pure_free;
+       type_struct->next_pure_free = * (char **)(type_struct->next_pure_free);
+       return((lispval) temp);
+}
+
+lispval
+newint()
+{
+       return(next_one(&int_str));
+}
+
+lispval
+pnewint()
+{
+       return(next_pure_one(&int_str));
+}
+
+lispval
+newdot()
+{
+       lispval temp;
+
+       temp = next_one(&dtpr_str);
+       temp->d.car = temp->d.cdr = nil;
+       return(temp);
+}
+
+lispval
+pnewdot()
+{
+       lispval temp;
+
+       temp = next_pure_one(&dtpr_str);
+       temp->d.car = temp->d.cdr = nil;
+       return(temp);
+}
+
+lispval
+newdoub()
+{
+       return(next_one(&doub_str));
+}
+
+lispval
+pnewdoub()
+{
+       return(next_pure_one(&doub_str));
+}
+
+lispval
+newsdot()
+{
+       register lispval temp;
+       temp = next_one(&sdot_str);
+       temp->d.car = temp->d.cdr = 0;
+       return(temp);
+}
+
+lispval
+pnewsdot()
+{
+       register lispval temp;
+       temp = next_pure_one(&sdot_str);
+       temp->d.car = temp->d.cdr = 0;
+       return(temp);
+}
+
+struct atom *
+newatom(pure) {
+       struct atom *save; char *mypname;
+
+       mypname = newstr(pure);
+       pnameprot = ((lispval) mypname);
+       save = (struct atom *) next_one(&atom_str) ;    
+       save->plist = save->fnbnd = nil;
+       save->hshlnk = (struct atom *)CNIL;
+       save->clb = CNIL;
+       save->pname = mypname;
+       return (save);
+}
+
+char *
+newstr(purep) {
+       char *save, *strcpy();
+       int atmlen;
+       register struct str_x *p = str_current + purep;
+
+       atmlen = strlen(strbuf)+1;
+       if(atmlen > p->space_left) {
+               if(atmlen >= STRBLEN) {
+                       save = (char *)csegment(OTHER, atmlen, purep);
+                       SETTYPE(save,STRNG,40);
+                       purepage[ATOX(save)] = (char)purep;
+                       strcpy(save,strbuf);
+                       return(save);
+               }
+               p->next_free =  (char *) (purep ?
+                       next_pure_one(&strng_str) : next_one(&strng_str)) ;
+               p->space_left = LBPG;
+       }
+       strcpy((save = p->next_free), strbuf);
+       /*while(atmlen & 3) ++atmlen;   /*  even up length of string  */
+       p->next_free += atmlen;
+       p->space_left -= atmlen;
+       return(save);
+}
+
+char *inewstr(s) char *s;
+{
+       strbuf[STRBLEN-1] = '\0';
+       strcpyn(strbuf,s,STRBLEN-1);
+       return(newstr(0));
+}
+
+char *pinewstr(s) char *s;
+{
+       strbuf[STRBLEN-1] = '\0';
+       strcpyn(strbuf,s,STRBLEN-1);
+       return(newstr(1));
+}
+
+lispval
+newarray()
+       {
+       register lispval temp;
+
+       temp = next_one(&array_str);
+       temp->ar.data = (char *)nil;
+       temp->ar.accfun = nil;
+       temp->ar.aux = nil;
+       temp->ar.length = SMALL(0);
+       temp->ar.delta = SMALL(0);
+       return(temp);
+       }
+
+lispval
+newfunct()
+       {
+       register lispval temp;
+       lispval badcall();
+       temp = next_one(&funct_str);
+       temp->bcd.start = badcall;
+       temp->bcd.discipline = nil;
+       return(temp);
+       }
+
+lispval
+newval()
+       {
+       register lispval temp;
+       temp = next_one(&val_str);
+       temp->l = nil;
+       return(temp);
+       }
+
+lispval
+pnewval()
+       {
+       register lispval temp;
+       temp = next_pure_one(&val_str);
+       temp->l = nil;
+       return(temp);
+       }
+
+lispval
+newhunk(hunknum)
+int hunknum;
+       {
+       register lispval temp;
+
+       temp = next_one(&hunk_str[hunknum]);    /* Get a hunk */
+       return(temp);
+       }
+
+lispval
+pnewhunk(hunknum)
+int hunknum;
+       {
+       register lispval temp;
+
+       temp = next_pure_one(&hunk_str[hunknum]);       /* Get a hunk */
+       return(temp);
+       }
+
+lispval
+inewval(arg) lispval arg;
+       {
+       lispval temp;
+       temp = next_one(&val_str);
+       temp->l = arg;
+       return(temp);
+       }
+
+/*
+ * Vector allocators.
+ * a vector looks like:
+ *  longword: N = size in bytes
+ *  longword: pointer to lisp object, this is the vector property field
+ *  N consecutive bytes
+ *
+ */
+lispval getvec();
+
+lispval
+newvec(size)
+{
+    return(getvec(size,&vect_str,FALSE));
+}
+
+lispval
+pnewvec(size)
+{
+    return(getvec(size,&vect_str,TRUE));
+}
+
+lispval
+nveci(size)
+{
+    return(getvec(size,&vecti_str,FALSE));
+}
+
+lispval
+pnveci(size)
+{
+    return(getvec(size,&vecti_str,TRUE));
+}
+
+/*
+ * getvec
+ *  get a vector of size byte, from type structure typestr and
+ * get it from pure space if purep is TRUE.
+ *  vectors are stored linked through their property field.  Thus
+ * when the code here refers to v.vector[0], it is the prop field
+ * and vl.vectorl[-1] is the size field.   In other code,
+ * v.vector[-1] is the prop field, and vl.vectorl[-2] is the size.
+ */
+lispval
+getvec(size,typestr,purep)
+register struct types *typestr;
+{
+    register lispval back, current;
+    int sizewant, bytes, thissize, pages, pindex, triedgc = FALSE;
+
+    /* we have to round up to a multiple of 4 bytes to determine the
+     * size of vector we want.  The rounding up assures that the
+     * property pointers are longword aligned
+     */
+    sizewant = VecTotSize(size);
+    if(debugin) fprintf(stderr,"want vect %db\n",size);    
+ again:
+    if(purep)
+        back = (lispval) &(typestr->next_pure_free);
+    else
+        back = (lispval) &(typestr->next_free);
+    current = back->v.vector[0];
+    while(current !=  CNIL)
+    {
+       if(debugin)
+            fprintf(stderr,"next free size %db; ", current->vl.vectorl[-1]);
+       if ((thissize = VecTotSize(current->vl.vectorl[-1])) == sizewant)
+       {
+           if(debugin) fprintf(stderr,"exact match of size %d at 0x%x\n",
+                               4*thissize, &current->v.vector[1]);
+           back->v.vector[0]
+               = current->v.vector[0];/* change free pointer*/
+           current->v.vector[0] = nil; /* put nil in property */
+           /* to the user, vector begins one after property*/
+           return((lispval)&current->v.vector[1]);
+       }
+       else if (thissize >= sizewant + 3)
+       {
+           /* the reason that there is a `+ 3' instead of `+ 2'
+            * is that we don't want to leave a zero sized vector which
+            * isn't guaranteed to be followed by another vector
+            */
+           if(debugin)
+            fprintf(stderr,"breaking a %d vector into a ",
+                                       current->vl.vectorl[-1]);
+
+           current->v.vector[1+sizewant+1]
+                       = current->v.vector[0];  /* free list pointer */
+           current->vl.vectorl[1+sizewant]
+                       = VecTotToByte(thissize - sizewant - 2);/*size info */
+           back->v.vector[0] = (lispval) &(current->v.vector[1+sizewant+1]);
+           current->vl.vectorl[-1] = size;
+
+           if(debugin)fprintf(stderr," %d one and a %d one\n",
+               current->vl.vectorl[-1],current->vl.vectorl[1+sizewant]);
+           current->v.vector[0] = nil; /* put nil in property */
+           /* vector begins one after the property */
+           if(debugin) fprintf(stderr," and returning vector at 0x%x\n",
+                               &current->v.vector[1]);
+           return((lispval)(&current->v.vector[1]));
+       }
+       back =  current;
+       current =  current->v.vector[0];
+    }
+    if(!triedgc
+        && !purep
+       && (gcdis->a.clb == nil)
+       && (initflag == FALSE))
+    {
+       gc(typestr);
+       triedgc = TRUE;
+       goto again;
+    }
+    
+    /* set bytes to size needed for this vector */
+    bytes = size + 2*sizeof(long);
+    
+    /* must make sure that if the vector we are allocating doesnt
+       completely fill a page, there is room for another vector to record
+       the size left over */
+    if((bytes & (LBPG - 1)) > (LBPG - 2*sizeof(long))) bytes += LBPG;
+    bytes = roundup(bytes,LBPG);
+
+    current = csegment(typestr->type,bytes/sizeof(long),purep);
+    current->vl.vectorl[0] = bytes - 2*sizeof(long);
+    
+    if(purep) {
+        current->v.vector[1] = (lispval)(typestr->next_pure_free);
+        typestr->next_pure_free = (char *) &(current->v.vector[1]);
+       /* make them pure */
+       pages = bytes/LBPG;
+       for(pindex = ATOX(current); pages ; pages--)
+       {
+           purepage[pindex++] = TRUE;
+       }
+    } else {
+        current->v.vector[1] = (lispval)(typestr->next_free);
+        typestr->next_free = (char *) &(current->v.vector[1]);
+       if(debugin) fprintf(stderr,"grabbed %d vec pages\n",bytes/LBPG);
+    }
+    if(debugin)
+      fprintf(stderr,"creating a new vec, size %d\n",current->v.vector[0]);
+    goto again;
+}
+
+/*
+ * Ipurep :: routine to check for pureness of a data item
+ *
+ */
+lispval 
+Ipurep(element)
+lispval element;
+{
+    if(purepage[ATOX(element)]) return(tatom) ; else return(nil);
+}
+
+/* routines to return space to the free list.  These are used by the
+ * arithmetic routines which tend to create large intermediate results
+ * which are know to be garbage after the calculation is over.
+ *
+ * There are jsb callable versions of these routines in qfuncl.s
+ */
+
+/* pruneb   - prune bignum. A bignum is an sdot followed by a list of
+ *  dtprs.    The dtpr list is linked by car instead of cdr so when we
+ *  put it in the free list, we have to change the links.
+ */
+pruneb(bignum)
+lispval bignum;
+{
+       register lispval temp = bignum;
+
+       if(TYPE(temp) != SDOT) 
+           errorh(Vermisc,"value to pruneb not a sdot",nil,FALSE,0);
+
+       --(sdot_items->i);
+       temp->s.I = (int) sdot_str.next_free;
+       sdot_str.next_free = (char *) temp;
+
+       /* bignums are not terminated by nil on the dual,
+          they are terminated by (lispval) 0 */
+
+       while(temp = temp->s.CDR)
+       {
+           if(TYPE(temp) != DTPR) 
+             errorh(Vermisc,"value to pruneb not a list",
+                     nil,FALSE,0);
+           --(dtpr_items->i);
+           temp->s.I = (int) dtpr_str.next_free;
+           dtpr_str.next_free = (char *) temp;
+       }
+}
+lispval
+badcall()
+       { error("BAD FUNCTION DESCRIPTOR USED IN CALL",FALSE); }
+
+
+
+/*
+ * Ngc 
+ *  this is the lisp function gc
+ *
+ */
+
+lispval
+Ngc()
+{
+    return(gc((struct types *)CNIL));
+}
+
+/*
+ * gc(type_struct) 
+ *
+ *  garbage collector:  Collects garbage by mark and sweep algorithm.
+ *  After this is done, calls the Nlambda, gcafter.
+ *  gc may also be called from LISP, as an  nlambda of no arguments.
+ * type_struct is the type of lisp data that ran out causing this
+ * garbage collection
+ */
+int printall = 0;
+lispval
+gc(type_struct)
+       struct types *type_struct;
+       {
+       lispval save;
+       struct tms begin, finish;
+       extern int gctime;
+
+       /* if this was called automatically when space ran out
+        * print out a message
+        */
+       if((Vgcprint->a.clb != nil)
+          && (type_struct != (struct types *) CNIL ))
+       {
+           FILE *port = okport(Vpoport->a.clb,poport);
+           fprintf(port,"gc:");
+           fflush(port);
+       }
+       
+       if(gctime) times(&begin);
+
+       gc1(); /* mark&sweep */
+
+       /* Now we call gcafter--special c ase if gc called from LISP */
+
+       if( type_struct == (struct types *) CNIL )
+               gccall1->d.cdr = nil;  /* make the call "(gcafter)" */
+       else
+               {
+               gccall1->d.cdr = gccall2;
+               gccall2->d.car = *(type_struct->type_name);
+               }
+       PUSHDOWN(gcdis,gcdis);  /*  flag to indicate in garbage collector  */
+       save = eval(gccall1);   /*  call gcafter  */
+       POP;                    /*  turn off flag  */
+
+       if(gctime) {
+               times(&finish);
+               gctime += (finish.tms_utime - begin.tms_utime);
+       }
+       return(save);   /*  return result of gcafter  */
+       }
+
+       
+
+/*  gc1()  **************************************************************/
+/*                                                                     */
+/*  Mark-and-sweep phase                                               */
+
+gc1()
+{
+       int j, k;
+       register int *start,bvalue,type_len; 
+       register struct types *s;
+       int *point,i,freecnt,itemstogo,bits,bindex,type,bytestoclear;
+       int usedcnt;
+       char *pindex;
+       struct argent *loop2;
+       struct nament *loop3;
+       struct atom *symb;
+       int markdp();
+       extern int hashtop;
+
+       pagerand(); 
+       /*  decide whether to check LISP structure or not  */
+
+
+#ifdef METER
+       vtimes(&premark,0);
+       markdpcount = 0;
+       conssame = consdiff = consnil = 0;
+#endif
+
+       /*  first set all bit maps to zero  */
+
+
+#ifdef SLOCLEAR
+       {
+           int enddat;
+           enddat = (int)(datalim-OFFSET) >> 8;
+           for(bvalue=0; bvalue < (int)enddat ; ++bvalue)
+           {
+                bitmapq[bvalue] = zeroq; 
+           }
+       }
+#endif
+
+       /* try the movc5 to clear the bit maps */
+       /* the maximum number of bytes we can clear in one sweep is
+        * 2^16 (or 1<<16 in the C lingo)
+        */
+       bytestoclear = ((((int)datalim)-((int)beginsweep)) >> 9) * 16; 
+       if(bytestoclear > MAXCLEAR)
+       { 
+          blzero(((int) &bitmapi[ATOLX(beginsweep)]) + MAXCLEAR, 
+                           bytestoclear - MAXCLEAR);
+          bytestoclear = MAXCLEAR;
+       }
+       blzero((int)&bitmapi[ATOLX(beginsweep)],bytestoclear);
+                       
+       /* mark all atoms in the oblist */
+        for( bvalue=0 ; bvalue <= hashtop-1 ; bvalue++ ) /* though oblist */
+        {
+           for( symb = hasht[bvalue] ; symb != (struct atom *) CNIL ;
+                     symb = symb-> hshlnk) {
+                 markdp((lispval)symb); 
+           }
+       }
+
+
+       /* Mark all the atoms and ints associated with the hunk
+          data types */
+          
+       for(i=0; i<7; i++) {
+               markdp(hunk_items[i]);
+               markdp(hunk_name[i]);
+               markdp(hunk_pages[i]);
+       }
+       /* next run up the name stack */
+       for(loop2 = np - 1; loop2 >=  orgnp; --loop2) MARKVAL(loop2->val);      
+
+       /* now the bindstack (vals only, atoms are marked elsewhere ) */
+       for(loop3 = bnp - 1; loop3 >= orgbnp; --loop3)MARKVAL(loop3->val);
+
+       
+       /* next mark all compiler linked data */
+       /* if the Vpurcopylits switch is non nil (lisp variable $purcopylits)
+        * then when compiled code is read in, it tables will not be linked
+        * into this table and thus will not be marked here.  That is ok
+        * though, since that data is assumed to be pure.
+        */
+        point = bind_lists;
+        while((start = point) != (int *)CNIL) {
+               while( *start != -1 )
+               {
+                       markdp((lispval)*start);
+                       start++;
+               }
+               point = (int *)*(point-1);
+        }
+
+       /* next mark all system-significant lisp data */
+
+       
+       for(i=0; i<SIGNIF; ++i) markdp((lispsys[i]));
+
+#ifdef METER
+       vtimes(&presweep,0);
+#endif
+       /* all accessible data has now been marked. */
+       /* all collectable spaces must be swept,    */
+       /* and freelists constructed.               */
+
+       /* first clear the structure elements for types
+        * we will sweep
+        */
+       
+       for(k=0 ; k <= VECTORI ; k++)
+       {
+               if( s=gcableptr[k]) {
+                   if(k==STRNG && !gcstrings) { /* don't do anything*/ }
+                   else
+                       {
+                         (*(s->items))->i = 0;
+                         s->space_left = 0;
+                         s->next_free = (char *) CNIL;
+                       }
+               }
+       }
+#if m_68k
+       fixbits(bitmapi+ATOLX(beginsweep),bitmapi+ATOLX(datalim));
+#endif
+
+
+       /* sweep up in memory looking at gcable pages */
+
+       for(start = beginsweep,  bindex = ATOLX(start), 
+                 pindex = &purepage[ATOX(start)]; 
+           start < (int *)datalim;
+           start += 128, pindex++)
+       {
+           if(!(s=gcableptr[type = TYPE(start)]) || *pindex
+#ifdef GCSTRINGS
+            || (type==STRNG && !gcstrings) 
+#endif
+               )
+           {
+               /* ignore this page but advance pointer         */
+               bindex += 4;   /* and 4 words of 32 bit bitmap words */
+               continue;
+           }
+
+           freecnt = 0;                /* number of free items found */
+           usedcnt = 0;                /* number of used items found */
+           
+           point = start;
+           /* sweep dtprs as a special case, since
+            * 1) there will (usually) be more dtpr pages than any other type
+            * 2) most dtpr pages will be empty so we can really win by special
+            *    caseing the sweeping of massive numbers of free cells
+            */
+           /* since sdot's have the same structure as dtprs, this code will
+              work for them too
+            */
+           if((type == DTPR) || (type == SDOT))
+           {
+               int *head,*lim;
+               head = (int *) s->next_free;    /* first value on free list*/
+
+               for(i=0; i < 4; i++)    /* 4 bit map words per page  */
+               {
+                   bvalue = bitmapi[bindex++]; /* 32 bits = 16 dtprs */
+                   if(bvalue == 0)     /* if all are free      */
+                   {
+                       *point = (int)head;
+                       lim = point + 32;   /* 16 dtprs = 32 ints */
+                       for(point += 2; point < lim ; point += 2)
+                       {
+                           *point = (int)(point - 2);
+                       }
+                       head = point - 2;
+                       freecnt += 16;
+                   }
+                   else for(j = 0; j < 16 ; j++)
+                   {
+                       if(!(bvalue & 1))
+                       {
+                           freecnt++;
+                           *point = (int)head;
+                           head = point;
+                       }
+#ifdef METER
+                       /* check if the page address of this cell is the
+                        * same as the address of its cdr
+                        */
+                       else if(FALSE && gcstat && (type == DTPR))
+                       {  
+                          if(((int)point & ~511) 
+                             == ((int)(*point) & ~511)) conssame++;
+                          else consdiff++;
+                          usedcnt++;
+                       }
+#endif
+                       else usedcnt++;         /* keep track of used */
+                       
+                       point += 2;
+                       bvalue = bvalue >> 2;
+                   }
+               }
+               s->next_free = (char *) head;
+           }
+           else if((type == VECTOR) || (type == VECTORI))
+           {
+               int canjoin = FALSE;
+               int *tempp;
+
+               /* check if first item on freelist ends exactly at
+                  this page
+                */
+               if(((tempp = (int *)s->next_free) != (int *)CNIL)
+                  && ((VecTotSize(((lispval)tempp)->vl.vectorl[-1])
+                                                           + 1 + tempp)
+                                       == point))
+                  canjoin = TRUE;
+                  
+               /* arbitrary sized vector sweeper */
+               /*
+                * jump past first word since that is a size fixnum
+                * and second word since that is property word
+                */
+               if(debugin)
+                 fprintf(stderr,"vector sweeping, start at 0x%x\n",
+                               point);
+               bits = 30;
+               bvalue = bitmapi[bindex++] >> 2;
+               point += 2;
+               while (TRUE) {
+                   type_len = point[VSizeOff];
+                   if(debugin) {
+                     fprintf(stderr,"point: 0x%x, type_len %d\n",
+                               point, type_len);
+                     fprintf(stderr,"bvalue: 0x%x, bits: %d, bindex: 0x%x\n",
+                               bvalue, bits, bindex);
+                   }
+                                       /* get size of vector */
+                   if(!(bvalue & 1))   /* if free */
+                   {
+                       if(debugin) fprintf(stderr,"free\n");
+                       freecnt += type_len + 2*sizeof(long);
+                       if(canjoin)
+                       {
+                           /* join by adjusting size of first vector */
+                           ((lispval)(s->next_free))->vl.vectorl[-1]
+                             +=  type_len + 2*sizeof(long); 
+                           if(debugin)
+                             fprintf(stderr,"joined size: %d\n",
+                                 ((lispval)(s->next_free))->vl.vectorl[-1]);
+                       }
+                       else {
+                           /* vectors are linked at the property word */
+                           *(point - 1) = (int)(s->next_free);
+                           s->next_free = (char *) (point - 1);
+                       }
+                       canjoin = TRUE;
+                   }
+                   else {
+                       canjoin = FALSE;
+                       usedcnt += type_len + 2*sizeof(long);
+                   }
+                   
+                   point += VecTotSize(type_len);
+                   /* we stop sweeping only when we reach a page
+                      boundary since vectors can span pages
+                    */
+                   if(((int)point & 511) == 0)
+                   {
+                       /* reset the counters, we cannot predict how
+                        * many pages we have crossed over
+                        */
+                       bindex = ATOLX(point);
+                       /* these will be inced, so we must dec */
+                       pindex = &purepage[ATOX(point)] - 1;
+                       start = point - 128;
+                       if(debugin)
+                       fprintf(stderr,
+                               "out of vector sweep when point = 0x%x\n",
+                               point);
+                       break;
+                   }
+                   /* must advance to next point and next value in bitmap.
+                    * we add VecTotSize(type_len) + 2 to get us to the 0th
+                    * entry in the next vector (beyond the size fixnum)
+                    */
+                   point += 2;         /* point to next 0th entry */
+                   if ( (bits -= (VecTotSize(type_len) + 2)) > 0)  
+                       bvalue = bvalue >> (VecTotSize(type_len) + 2);
+                   else {
+                       bits = -bits;   /* must advance to next word in map */
+                       bindex += bits / 32; /* this is tricky stuff... */
+                       bits = bits % 32;
+                       bvalue = bitmapi[bindex++] >> bits;
+                       bits = 32 - bits;
+                   }
+               }
+           }
+           else { 
+               /* general sweeper, will work for all types */
+               itemstogo = s->space;   /* number of items per page  */
+               bits = 32;                      /* number of bits per word */
+               type_len = s->type_len;
+
+               /* printf(" s %d, itemstogo %d, len %d\n",s,itemstogo,type_len);*/
+               bvalue = bitmapi[bindex++];
+
+               while(TRUE)
+               {
+                   if(!(bvalue & 1))   /* if data element is not marked */
+                   {
+                       freecnt++;
+                       *point = (int) (s->next_free) ;
+                       s->next_free = (char *) point;
+                   }
+                   else usedcnt++;
+
+                   if( --itemstogo <= 0 ) 
+                   {    if(type_len >= 64) 
+                        {
+                           bindex++;
+                           if(type_len >=128) bindex += 2;
+                        }
+                        break;
+                   }
+
+                   point += type_len;
+                   /* shift over mask by number of words in data type */
+
+                   if( (bits -= type_len) > 0)
+                   {  bvalue = bvalue >> type_len;
+                   } 
+                   else if( bits == 0 ) 
+                   {  bvalue = bitmapi[bindex++];
+                      bits = 32;
+                   }
+                   else
+                   {  bits = -bits;
+                      while( bits >= 32) { bindex++;
+                                           bits -= 32;
+                                         }
+                      bvalue = bitmapi[bindex++];
+                      bvalue = bvalue >> bits;
+                      bits = 32 - bits;;
+                   }
+           }
+       }
+
+     s->space_left += freecnt;
+     (*(s->items))->i += usedcnt;
+     }
+
+#ifdef METER
+        vtimes(&alldone,0);
+       if(gcstat) gcdump();
+#endif
+       pagenorm(); 
+}
+
+/*
+ * alloc
+ *
+ *  This routine tries to allocate one or more pages of the space named
+ *  by the first argument.   Returns the number of pages actually allocated.
+ *  
+ */
+
+lispval
+alloc(tname,npages)
+lispval tname; long npages;
+{
+       long ii, jj;
+       struct types *typeptr;
+
+       ii = typenum(tname);
+        typeptr = spaces[ii];
+       if(npages <= 0) return(inewint(npages));
+       
+       if((ATOX(datalim)) + npages > TTSIZE)
+          error("Space request would exceed maximum memory allocation",FALSE);
+       if((ii == VECTOR) || (ii == VECTORI))
+       {
+           /* allocate in one big chunk */
+           tname = csegment((int) ii,(int) npages*128,0);
+           tname->vl.vectorl[0] = (npages*512 - 2*sizeof(long));
+           tname->v.vector[1] = (lispval) typeptr->next_free;
+           typeptr->next_free = (char *) &(tname->v.vector[1]);
+           if(debugin) fprintf(stderr,"alloced %d vec pages\n",npages);
+           return(inewint(npages));
+       }
+          
+       for( jj=0; jj<npages; ++jj)
+               if(get_more_space(spaces[ii],FALSE)) break;
+       return(inewint(jj));
+}
+
+/*
+ * csegment(typecode,nitems,useholeflag)
+ *  allocate nitems of type typecode.  If useholeflag is true, then
+ * allocate in the hole if there is room.  This routine doesn't look
+ * in the free lists, it always allocates space.
+ */    
+lispval
+csegment(typecode,nitems,useholeflag)
+{
+       register int ii, jj;
+       register char *charadd;
+
+       ii = typecode;
+
+       if(ii!=OTHER) nitems *= 4*spaces[ii]->type_len;
+       nitems = roundup(nitems,512);           /*  round up to right length  */
+#ifdef HOLE
+       if(useholeflag)
+               charadd = gethspace(nitems,ii);
+       else
+#endif
+       {
+               charadd = sbrk(nitems);
+               datalim = (lispval)(charadd+nitems);
+       }
+       if( (int) charadd == 0 )
+               error("NOT ENOUGH SPACE FOR ARRAY",FALSE);
+       /*if(ii!=OTHER)*/ (*spaces[ii]->pages)->i +=  nitems/512;
+       if(ATOX(datalim) > fakettsize) {
+               datalim = (lispval) (OFFSET + (fakettsize << 9));
+               if(fakettsize >= TTSIZE)
+               {
+                   printf("There isn't room enough to continue, goodbye\n");
+                   franzexit(1);
+               }
+               fakettsize++;
+               badmem(53);
+       }
+       for(jj=0; jj<nitems; jj=jj+512) {
+               SETTYPE(charadd+jj, ii,30);
+       }
+       ii = (int) charadd;
+       while(nitems > MAXCLEAR)
+       {
+           blzero(ii,MAXCLEAR);
+           nitems -= MAXCLEAR;
+           ii += MAXCLEAR;
+       }
+       blzero(ii,nitems);
+       return((lispval)charadd);
+}
+
+int csizeof(tname) lispval tname;
+       {
+       return( spaces[typenum(tname)]->type_len * 4 );
+       }
+
+int typenum(tname) lispval tname;
+       {
+       int ii;
+
+chek:  for(ii=0; ii<NUMSPACES; ++ii)
+               if(spaces[ii] && tname == *(spaces[ii]->type_name)) break;
+       if(ii == NUMSPACES)
+               {
+               tname = error("BAD TYPE NAME",TRUE);
+               goto chek;
+               }
+
+       return(ii);
+       
+       }
+char *
+gethspace(segsiz,type)
+{
+       extern usehole; extern char holend[]; extern char *curhbeg;
+       register char *value;
+
+       if(usehole) {   
+               curhbeg = (char *) roundup(((int)curhbeg),LBPG);
+               if((holend - curhbeg) < segsiz)
+               {       printf("[fasl hole filled up]\n");
+                       usehole = FALSE;
+                       curhbeg = holend;
+               } else {
+                       value = curhbeg;
+                       curhbeg = curhbeg + segsiz;
+                       /*printf("start %d, finish %d, size %d\n",value, curhbeg,segsiz);*/
+                       return(value);
+               }
+       }
+       value = (ysbrk(segsiz/LBPG,type));
+       datalim = (lispval)(value + segsiz);
+       return(value);
+}
+gcrebear()
+{
+#ifdef HOLE
+        register int i; register struct types *p;
+
+       /* this gets done upon rebirth */
+       str_current[1].space_left = 0;
+#ifndef GCSTRINGS
+       str_current[0].space_left = 0;  /* both kinds of strings go in hole*/
+#endif
+       funct_str.space_left = 0;
+       funct_str.next_free = (char *) CNIL;
+       /* clear pure space pointers */
+       for(i = 0; i < NUMSPACES; i++)
+       {
+           if(p=spaces[i])
+           p->next_pure_free = (char *) CNIL;
+       }
+#endif
+}
+
+/** markit(p) ***********************************************************/
+/*  just calls markdp                                                  */
+
+markit(p) lispval *p; { markdp(*p); }
+
+/*
+ * markdp(p)
+ *
+ *  markdp is the routine which marks each data item.  If it is a
+ *  dotted pair, the car and cdr are marked also.
+ *  An iterative method is used to mark list structure, to avoid
+ *  excessive recursion.
+ */
+markdp(p) register lispval p;
+       {
+/*     register int r, s;      (goes with non-asm readbit, oksetbit)   */
+/*     register hsize, hcntr;                                          */
+       int hsize, hcntr;
+
+#ifdef METER
+       markdpcount++;
+#endif
+ptr_loop:
+       if(((int)p) <= ((int)nil)) return;      /*  do not mark special data types or nil=0  */
+
+               
+       switch( TYPE(p) )
+               {
+               case ATOM:
+                       ftstbit;
+                       MARKVAL(p->a.clb);
+                       MARKVAL(p->a.plist);
+                       MARKVAL(p->a.fnbnd);
+#ifdef GCSTRINGS
+                       if(gcstrings) MARKVAL(((lispval)p->a.pname));
+                       return;
+
+               case STRNG:
+                       p = (lispval) (((int) p) & ~ (LBPG-1));
+                       ftstbit;
+#endif
+                       return;
+                       
+               case INT:
+               case DOUB:
+                       ftstbit;
+                       return;
+               case VALUE:
+                       ftstbit;
+                       p = p->l;
+                       goto ptr_loop;
+               case DTPR:
+                       ftstbit;
+                       MARKVAL(p->d.car);
+#ifdef METER
+                       /* if we are metering , then check if the cdr is
+                        * nil, or if the cdr is on the same page, and if
+                        * it isn't one of those, then it is on a different
+                        * page
+                        */
+                        if(gcstat)
+                        {
+                            if(p->d.cdr == nil) consnil++;
+                            else if(((int)p & ~511) 
+                                    == (((int)(p->d.cdr)) & ~511))
+                               conssame++;
+                            else consdiff++;
+                         }
+#endif
+                       p = p->d.cdr;
+                       goto ptr_loop;
+
+               case ARRAY:
+                       ftstbit;        /* mark array itself */
+
+                       MARKVAL(p->ar.accfun);  /* mark access function */
+                       MARKVAL(p->ar.aux);             /* mark aux data */
+                       MARKVAL(p->ar.length);  /* mark length */
+                       MARKVAL(p->ar.delta);   /* mark delta */
+                       if(TYPE(p->ar.aux)==DTPR && p->ar.aux->d.car==Vnogbar)
+                       {
+                           /* a non garbage collected array must have its
+                            * array space marked but the value of the array
+                            * space is not marked
+                            */
+                            int l; 
+                            int cnt,d;
+                            if(debugin && FALSE) {
+                              printf("mark array holders len %d, del %d, start 0x%x\n",
+                                p->ar.length->i,p->ar.delta->i,p->ar.data);
+                                fflush(stdout);
+                           }
+                            l = p->ar.length->i; /* number of elements */
+                            d = p->ar.delta->i;  /* bytes per element  */
+                            p = (lispval) p->ar.data;/* address of first one*/
+                            if(purepage[ATOX(p)]) return;
+
+                            for((cnt = 0); cnt<l ; 
+                                     p = (lispval)(((char *) p) + d), cnt++)
+                            {
+                               setbit;
+                            }
+                       } else {
+/*                     register int i, l; int d;               */
+/*                     register char *dataptr = p->ar.data;    */
+                       int i,l,d;
+                       char *dataptr = p->ar.data;
+
+                       for(i=0, l=p->ar.length->i, d=p->ar.delta->i; i<l; ++i)
+                               {
+                               markdp((lispval)dataptr);
+                               dataptr += d;
+                               }
+                       }
+                       return;
+               case SDOT:
+                       do {
+                               ftstbit;
+                               p = p->s.CDR;
+                       } while (p!=0);
+                       return;
+
+               case BCD:
+                       ftstbit;
+                       markdp(p->bcd.discipline);
+                       return;
+
+               case HUNK2:
+               case HUNK4:
+               case HUNK8:
+               case HUNK16:
+               case HUNK32:
+               case HUNK64:
+               case HUNK128:
+                       {
+                               hsize = 2 << HUNKSIZE(p);
+                               ftstbit;
+                               for (hcntr = 0; hcntr < hsize; hcntr++)
+                                       MARKVAL(p->h.hunk[hcntr]);
+                               return;
+                       }
+                       
+               case VECTORI:
+                       ftstbit;
+                       MARKVAL(p->v.vector[-1]);       /* mark property */
+                       return;
+                       
+               case VECTOR:
+                       {
+                           register int vsize;
+                           ftstbit;
+                           vsize = VecSize(p->vl.vectorl[VSizeOff]);
+                           if(debugin)
+                              fprintf(stderr,"mark vect at %x  size %d\n",
+                                       p,vsize);
+                           while(--vsize >= -1)
+                           {
+                               MARKVAL(p->v.vector[vsize]);
+                           };
+                           return;
+                       }
+               }
+       return;
+       }
+
+
+/* xsbrk allocates space in large chunks (currently 16 pages)
+ * xsbrk(1)  returns a pointer to a page
+ * xsbrk(0)  returns a pointer to the next page we will allocate (like sbrk(0))
+ */
+
+char *
+xsbrk(n)
+       {
+       static char *xx;        /*  pointer to next available blank page  */
+       extern int xcycle;      /*  number of blank pages available  */
+       lispval u;                      /*  used to compute limits of bit table  */
+
+       if( (xcycle--) <= 0 )
+               {
+               xcycle = 15;
+               xx = sbrk(16*LBPG);     /*  get pages 16 at a time  */
+               if( (int)xx== -1 )
+                       lispend("For sbrk from lisp: no space... Goodbye!");
+               }
+       else xx += LBPG;
+
+       if(n == 0)
+       {
+           xcycle++;   /* don't allocate the page */
+           xx -= LBPG;
+           return(xx); /* just return its address */
+       }
+
+       if( (u = (lispval)(xx+LBPG))  > datalim ) datalim = u;
+       return(xx);
+       }
+
+char *ysbrk(pages,type) int pages, type;
+       {
+       char *xx;       /*  will point to block of storage  */
+       int i;
+
+       xx = sbrk(pages*LBPG);
+       if((int)xx == -1)
+               error("OUT OF SPACE FOR ARRAY REQUEST",FALSE);
+
+       datalim = (lispval)(xx+pages*LBPG);     /*  compute bit table limit  */
+
+       /*  set type for pages  */
+
+       for(i = 0; i < pages; ++i) {
+               SETTYPE((xx + i*LBPG),type,10);
+       }
+
+       return(xx);     /*  return pointer to block of storage  */
+       }
+       
+/*
+ * getatom 
+ * returns either an existing atom with the name specified in strbuf, or
+ * if the atom does not already exist, regurgitates a new one and 
+ * returns it.
+ */
+lispval
+getatom(purep)
+{   register lispval aptr;
+    register char *name, *endname;
+    register int hash;
+    lispval    b;
+    char       c;
+
+       name = strbuf;
+       if (*name == (char)0377) return (eofa);
+       hash = hashfcn(name);
+       atmlen = strlen(name) + 1;
+       aptr = (lispval) hasht[hash];
+       while (aptr != CNIL)
+           if (strcmp(name,aptr->a.pname)==0)
+               return (aptr);
+           else
+               aptr = (lispval) aptr->a.hshlnk;
+       aptr = (lispval) newatom(purep);  /*share pname of atoms on oblist*/
+       aptr->a.hshlnk = hasht[hash];
+       hasht[hash] = (struct atom *) aptr;
+       endname = name + atmlen - 2;
+       if ((atmlen != 4) && (*name == 'c') && (*endname == 'r'))
+               {
+               b = newdot();
+               protect(b);
+               b->d.car = lambda;
+               b->d.cdr = newdot();
+               b = b->d.cdr;
+               b->d.car = newdot();
+               (b->d.car)->d.car = xatom;
+               while(TRUE)
+                       {
+                       b->d.cdr = newdot();
+                       b= b->d.cdr;
+                       if(++name == endname)
+                               {
+                               b->d.car= (lispval) xatom;
+                               aptr->a.fnbnd = (--np)->val;
+                               break;
+                               }
+                       b->d.car= newdot();
+                       b= b->d.car;
+                       if((c = *name) == 'a') b->d.car = cara;
+                       else if (c == 'd') b->d.car = cdra;
+                       else{ --np;
+                          break;
+                        }
+                       }
+               }
+
+       return(aptr);
+       }
+
+/* our hash function */
+
+hashfcn(symb)
+register char *symb;
+{
+       register int i;
+       for (i=0 ; *symb ; i += i + *symb++);
+       return(i & (HASHTOP-1));
+}
+
+lispval
+LImemory()
+{
+    int nextadr, pagesinuse;
+    
+    printf("Memory report. max pages = %d (0x%x) = %d Bytes\n",
+               TTSIZE,TTSIZE,TTSIZE*LBPG);
+#ifdef HOLE
+        printf("This lisp has a hole:\n");
+       printf("  current hole start: %d (0x%x), end %d (0x%x)\n",
+               curhbeg, curhbeg, holend, holend);
+       printf("  hole free: %d bytes = %d pages\n\n",
+              holend-curhbeg, (holend-curhbeg)/LBPG);
+#endif 
+    nextadr = (int) xsbrk(0);  /* next space to be allocated */
+    pagesinuse = nextadr/LBPG;
+    printf("Next allocation at addr %d (0x%x) = page %d\n",
+                       nextadr, nextadr, pagesinuse);
+    printf("Free data pages: %d\n", TTSIZE-pagesinuse);
+    return(nil);
+}
+
+extern struct atom *hasht[HASHTOP];
+myhook(){}
diff --git a/usr/src/ucb/lisp/franz/data.c b/usr/src/ucb/lisp/franz/data.c
new file mode 100644 (file)
index 0000000..ccdc4ad
--- /dev/null
@@ -0,0 +1,289 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: data.c,v 1.7 83/09/12 14:17:15 sklower Exp $";
+#endif
+
+/*                                     -[Sun Jun 19 14:41:00 1983 by jkf]-
+ *     data.c                          $Locker:  $
+ * static storage declarations
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+
+#include       "global.h"
+#include       "gtabs.h"
+#include       "structs.h"
+#include       "frame.h"
+#include       <stdio.h>
+
+/*char firstalloc[NBPG] = { 'x' };     /* first thing allocated in file */
+lispval lispsys[SIGNIF];       /* lisp data used by system */
+
+lispval gftab[GFTABLEN];       /* global function table for interpreter */
+
+lispval gctab[GCTABLEN] =      /* global constant table for interpreter */
+       {nil,0,SMALL(-1),SMALL(0),SMALL(1),SMALL(2),SMALL(3),SMALL(4)};
+
+
+/* Port definitions *****************************************************/
+FILE   *piport,                /* standard input port          */
+       *poport,                /* standard output port         */
+       *errport,               /* port for error messages      */
+       *rdrport,               /* temporary port for readr     */
+       *proport;               /* port for protocal            */
+int    lineleng =      80;             /* line length desired          */
+int    rlevel;                 /* used to indicate depth of recursion
+                                  in reader.  No longer really necessary */
+char   keybin =        FALSE;          /* logical flag: using keyboard */
+char   protflag =      FALSE;          /* logical flag: want protocall */
+char   rbktf;                          /* logical flag: ] mode         */
+
+lispval ioname[_NFILE];                /* strings of names of files currently open     */
+
+/* name stack ***********************************************************/
+struct argent *orgnp;          /* used by top level to reset to start  */
+struct argent          *namptr,                /* temporary pointer    */
+#ifndef NPINREG
+                       *lbot,                  /* beginning of frame   */
+                       *np,                    /* first free entry     */
+#endif
+                       *nplim;                 /* don't have this = np */
+struct nament          *bnp,                   /* top of bind stack    */
+                       *orgbnp,                /* absolute bottom of ""*/
+                       *bnplim;                /* absolute top of ""   */
+
+
+
+/* hashing things *******************************************************/
+int    hash;                                   /* set by ratom         */
+int    atmlen;                 /* length of atom including final null  */
+
+
+/* big string buffer for whomever needs it ******************************/
+static char    i_strbuf[600];
+char   *strbuf         = i_strbuf;
+char   *endstrb        = i_strbuf + 599;
+
+/* in the case we can't use the C stack for extending automatics */
+#ifdef SPISFP
+long xstack[16384];
+long *xsp;
+long *exsp = xstack + ((sizeof xstack)/(sizeof (long)));
+#endif
+
+/* strings needed by the two hand crafted atoms, nil and eof */
+char nilpname[] = "nil";
+char eofpname[] = "eof";
+
+/* set by sstatus commands */
+int uctolc = 0;                /* when set, uc chars in atoms go to lc */
+                       /* default mode for dumplisp 
+                          (note this is decimal not octal) */
+#if os_unisoft || os_unix_ts
+int dmpmode = 410;
+#else
+int dmpmode = 413;
+#endif
+
+/* break and error declarations *****************************************/
+int    depth = 0;              /* depth of nested breaks               */
+lispval        contval;                /* the value being returned up          */
+int    retval;                 /* used by each error/prog call         */
+lispval lispretval;            /* used by non-local goto's             */
+int    rsetsw;                 /* when set, trace frames built         */
+int    bcdtrsw;                /* when set with rsetsw, trace bcd too  */
+int    evalhcallsw;            /* when set will not evalhook next eval */
+int    funhcallsw;             /* when set will not funcallhook next eval */
+
+
+/* exception handling stuff *********************************************/
+int exception;                 /* true if an exception is pending */
+int sigintcnt;                 /* number of SIGINT's pending      */
+
+/* current state of the hole (for fasling into) *************************/
+#ifndef HOLE
+#define HOLE 0
+#endif
+extern char holbeg[];
+char *curhbeg = holbeg;                        /* next location to fasl into */
+int usehole = HOLE;                    /* if TRUE, fasl tries to use hole */
+int holesize = HOLE;                   /* This avoids an ifdef in dumplisp */
+
+/* other stuff **********************************************************/
+lispval        ftemp,vtemp,argptr,ttemp;       /* temporaries: use briefly     */
+int itemp;
+lispval sigacts[16];                   /* for catching interrupts      */
+int sigstruck,sigdelay;                        /* for catching interrupts      */
+lispval stattab[16];                   /* miscelleneous options        */
+lispval Vprintsym;                     /* value is the symbol 'print'  */
+
+/*  interpreter globals    */
+
+int lctrace;
+int fvirgin = 1;               /* set to 1 initially                   */
+int gctime;
+struct frame *errp;            /* stack of error frames                */
+
+
+/* global pointers to the transfer tables */
+
+
+struct trtab *trhead=          /* first in list of transfer tables        */
+      (struct trtab *) 0;
+struct trent *trcur;           /* next entry to allocate                  */
+int trleft = 0;                        /* number of entries left in current table */
+
+/* globals from sysat.c  */
+
+int *beginsweep;               /* place for sweeper to begin           */
+int initflag = TRUE;           /* inhibit gcing initially              */
+int tgcthresh = 15;
+int page_limit = (5 * TTSIZE) / 6;
+int ttsize = TTSIZE;
+
+
+/* global used in io.c */
+
+lispval lastrtab;
+
+/* globals from [VT]alloc.c  */
+
+
+char purepage[TTSIZE];
+int fakettsize = TTSIZE - 8;
+int gcstrings;                         /*  Do we mark and sweep strings? */
+int  *bind_lists = (int *) CNIL;       /*  lisp data for compiled code */
+
+
+struct str_x str_current[2];           /*  next free string spaces */
+
+struct types
+       atom_str =
+       {
+               (char *)CNIL,   0,      ATOMSPP,        ATOM,   5,
+               &atom_items,    &atom_pages,    &atom_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+       strng_str =
+       {
+               (char *) CNIL,  0,      STRSPP,         STRNG,  128,
+               &str_items,     &str_pages,     &str_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+       int_str =
+       {
+               (char *) CNIL,  0,      INTSPP,         INT,    1,
+               &int_items,     &int_pages,     &int_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+       dtpr_str =
+       {
+               (char *) CNIL,  0,      DTPRSPP,        DTPR,   2,
+               &dtpr_items,    &dtpr_pages,    &dtpr_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+       doub_str =
+       {
+               (char *) CNIL,  0,      DOUBSPP,        DOUB,   2,
+               &doub_items,    &doub_pages,    &doub_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+       array_str =
+       {
+               (char *) CNIL,  0,      ARRAYSPP,       ARRAY,  5,
+               &array_items,   &array_pages,   &array_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+       other_str =
+       {
+               (char *) CNIL,  0,      STRSPP,         OTHER,  128,
+               &other_items,   &other_pages,   &other_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+
+       sdot_str =
+       {
+               (char *) CNIL,  0,      SDOTSPP,        SDOT,   2,
+               &sdot_items,    &sdot_pages,    &sdot_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+       val_str =
+       {
+               (char *) CNIL,  0,      VALSPP,         VALUE,  1,
+               &val_items,     &val_pages,     &val_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+funct_str =
+       {
+               (char *) CNIL,  0,      BCDSPP,         BCD,    2,
+               &funct_items,   &funct_pages,   &funct_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+vect_str =
+       {
+               
+               (char *) CNIL,  0,      VECTORSPP,      VECTOR, 1,
+               &vect_items,    &vect_pages,    &vect_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+vecti_str =
+       {
+               
+               (char *) CNIL,  0,      VECTORSPP,      VECTORI, 1,
+               &vect_items,    &vecti_pages,   &vecti_name,
+               (struct heads *) CNIL, (char *)CNIL
+       },
+
+hunk_str[7] =
+       {
+               {
+                       (char *) CNIL,  0,      HUNK2SPP,       HUNK2,  2,
+                       &hunk_items[0], &hunk_pages[0], &hunk_name[0],
+                       (struct heads *) CNIL, (char *)CNIL
+               },
+               {
+                       (char *) CNIL,  0,      HUNK4SPP,       HUNK4,  4,
+                       &hunk_items[1], &hunk_pages[1], &hunk_name[1],
+                       (struct heads *) CNIL, (char *)CNIL
+               },
+               {
+                       (char *) CNIL,  0,      HUNK8SPP,       HUNK8,  8,
+                       &hunk_items[2], &hunk_pages[2], &hunk_name[2],
+                       (struct heads *) CNIL, (char *)CNIL
+               },
+               {
+                       (char *) CNIL,  0,      HUNK16SPP,      HUNK16, 16,
+                       &hunk_items[3], &hunk_pages[3], &hunk_name[3],
+                       (struct heads *) CNIL, (char *)CNIL
+               },
+               {
+                       (char *) CNIL,  0,      HUNK32SPP,      HUNK32, 32,
+                       &hunk_items[4], &hunk_pages[4], &hunk_name[4],
+                       (struct heads *) CNIL, (char *)CNIL
+               },
+               {
+                       (char *) CNIL,  0,      HUNK64SPP,      HUNK64, 64,
+                       &hunk_items[5], &hunk_pages[5], &hunk_name[5],
+                       (struct heads *) CNIL, (char *)CNIL
+               },
+               {
+                       (char *) CNIL,  0,      HUNK128SPP,     HUNK128, 128,
+                       &hunk_items[6], &hunk_pages[6], &hunk_name[6],
+                       (struct heads *) CNIL, (char *)CNIL
+               }
+       };
+extern struct readtable { unsigned char        ctable[132]; } initread;
+unsigned char *ctable = initread.ctable;
+int gensymcounter = 0;
+
+int hashtop = HASHTOP;
+int xcycle = 0;                /* used by xsbrk   */
+struct atom *hasht[HASHTOP];
+lispval datalim;       /* pointer to next location to allocate */
+
+char typetable[TTSIZE+1] = {UNBO,ATOM,PORT,INT,INT,INT,INT,INT,INT,INT,INT,INT,INT,INT,INT,INT,INT,INT,INT};
+
+/* this must be the last thing allocated in this file  */
+char lsbrkpnt,zfreespace;
diff --git a/usr/src/ucb/lisp/franz/divbig.c b/usr/src/ucb/lisp/franz/divbig.c
new file mode 100644 (file)
index 0000000..4df6c92
--- /dev/null
@@ -0,0 +1,452 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: divbig.c,v 1.3 83/09/12 14:17:07 sklower Exp $";
+#endif
+
+/*                                     -[Sat Jan 29 12:22:36 1983 by jkf]-
+ *     divbig.c                                $Locker:  $
+ * bignum division
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+
+#define b 0x40000000
+#define toint(p) ((int) (p))
+
+divbig(dividend, divisor, quotient, remainder)
+lispval dividend, divisor, *quotient, *remainder;
+{
+       register *ujp, *vip;
+       int *alloca(), d, negflag = 0, m, n, carry, rem, qhat, j;
+       int borrow, negrem = 0;
+       long *utop = sp(), *ubot, *vbot, *qbot;
+       register lispval work; lispval export();
+       Keepxs();
+
+       /* copy dividend */
+       for(work = dividend; work; work = work ->s.CDR)
+               stack(work->s.I);
+       ubot = sp();
+       if(*ubot < 0) {         /* knuth's division alg works only for pos
+                                       bignums                         */
+               negflag ^= 1;
+               negrem = 1;
+               dsmult(utop-1,ubot,-1);
+       }
+       stack(0);
+       ubot = sp();
+
+       
+       /*copy divisor */
+       for(work = divisor; work; work = work->s.CDR)
+               stack(work->s.I);
+
+       vbot = sp();
+       stack(0);
+       if(*vbot < 0) {
+               negflag ^= 1;
+               dsmult(ubot-1,vbot,-1);
+       }
+
+       /* check validity of data */
+       n = ubot - vbot;
+       m = utop - ubot - n - 1;
+       if (n == 1) {
+               /* do destructive division by  a single. */
+               rem = dsdiv(utop-1,ubot,*vbot);
+               if(negrem)
+                       rem = -rem;
+               if(negflag)
+                       dsmult(utop-1,ubot,-1);
+               if(remainder)
+                       *remainder = inewint(rem);
+               if(quotient)
+                       *quotient = export(utop,ubot);
+               Freexs();
+               return;
+       }
+       if (m < 0) {
+               if (remainder)
+                       *remainder = dividend;
+               if(quotient)
+                       *quotient = inewint(0);
+               Freexs();
+               return;
+       }
+       qbot = alloca(toint(utop) + toint(vbot) - 2 * toint(ubot));
+d1:
+       d = b /(*vbot +1);
+       dsmult(utop-1,ubot,d);
+       dsmult(ubot-1,vbot,d);
+
+d2:    for(j=0,ujp=ubot; j <= m; j++,ujp++) {
+
+       d3:     
+               qhat = calqhat(ujp,vbot);
+       d4:
+               if((borrow = mlsb(ujp + n, ujp, ubot, -qhat)) < 0) {
+                       adback(ujp + n, ujp, ubot);
+                       qhat--;
+               }
+               qbot[j] = qhat;
+       }
+d8:    if(remainder) {
+               dsdiv(utop-1, utop - n, d);
+               if(negrem) dsmult(utop-1,utop-n,-1);
+               *remainder = export(utop,utop-n);
+       }
+       if(quotient) {
+               if(negflag)
+                       dsmult(qbot+m,qbot,-1);
+               *quotient = export(qbot + m + 1, qbot);
+       }
+       Freexs();
+}
+/*
+ * asm code commented out due to optimizer bug
+ * also, this file is now shared with the 68k version!
+calqhat(ujp,v1p)
+register int *ujp, *v1p;
+{
+asm("  cmpl    (r10),(r11)             # v[1] == u[j] ??");
+asm("  beql    2f                      ");
+asm("  # calculate qhat and rhat simultaneously,");
+asm("  #  qhat in r0");
+asm("  #  rhat in r1");
+asm("  emul    (r11),$0x40000000,4(r11),r4 # u[j]b+u[j+1] into r4,r5");
+asm("  ediv    (r10),r4,r0,r1          # qhat = ((u[j]b+u[j+1])/v[1]) into r0");
+asm("                                  # (u[j]b+u[j+1] -qhat*v[1]) into r1");
+asm("                                  # called rhat");
+asm("1:");
+asm("  # check if v[2]*qhat > rhat*b+u[j+2]");
+asm("  emul    r0,4(r10),$0,r2         # qhat*v[2] into r3,r2");
+asm("  emul    r1,$0x40000000,8(r11),r8 #rhat*b + u[j+2] into r9,r8");
+asm("  # give up if r3,r2 <= r9,r8, otherwise iterate");
+asm("  subl2   r8,r2                   # perform r3,r2 - r9,r8");
+asm("  sbwc    r9,r3");
+asm("  bleq    3f                      # give up if negative or equal");
+asm("  decl    r0                      # otherwise, qhat = qhat - 1");
+asm("  addl2   (r10),r1                # since dec'ed qhat, inc rhat by v[1]");
+asm("  jbr     1b");
+asm("2:        ");
+asm("  # get here if v[1]==u[j]");
+asm("  # set qhat to b-1");
+asm("  # rhat is easily calculated since if we substitute b-1 for qhat in");
+asm("  # the formula, then it simplifies to (u[j+1] + v[1])");
+asm("  # ");
+asm("  addl3   4(r11),(r10),r1         # rhat = u[j+1] + v[1]");
+asm("  movl    $0x3fffffff,r0          # qhat = b-1");
+asm("  jbr     1b");
+asm("3:");
+}
+mlsb(utop,ubot,vtop,nqhat)
+register int *utop, *ubot, *vtop;
+register int nqhat;
+{
+asm("  clrl    r0");
+asm("loop2:    addl2   (r11),r0");
+asm("  emul    r8,-(r9),r0,r2");
+asm("  extzv   $0,$30,r2,(r11)");
+asm("  extv    $30,$32,r2,r0");
+asm("  acbl    r10,$-4,r11,loop2");
+}
+adback(utop,ubot,vtop)
+register int *utop, *ubot, *vtop;
+{
+asm("  clrl    r0");
+asm("loop3:    addl2   -(r9),r0");
+asm("  addl2   (r11),r0");
+asm("  extzv   $0,$30,r0,(r11)");
+asm("  extv    $30,$2,r0,r0");
+asm("  acbl    r10,$-4,r11,loop3");
+}
+dsdiv(top,bot,div)
+register int* bot;
+{
+asm("  clrl    r0");
+asm("loop4:    emul    r0,$0x40000000,(r11),r1");
+asm("  ediv    12(ap),r1,(r11),r0");
+asm("  acbl    4(ap),$4,r11,loop4");
+}
+dsmult(top,bot,mult)
+register int* top;
+{
+asm("  clrl    r0");
+asm("loop5:    emul    12(ap),(r11),r0,r1");
+asm("  extzv   $0,$30,r1,(r11)");
+asm("  extv    $30,$32,r1,r0");
+asm("  acbl    8(ap),$-4,r11,loop5");
+asm("  movl    r1,4(r11)");
+}
+*/
+lispval
+export(top,bot)
+register long *top, *bot;
+{
+       register lispval p;
+       lispval result;
+
+       top--; /* screwey convention matches original
+                 vax assembler convenience */
+       while(bot < top)
+       {
+               if(*bot==0)
+                       bot++;
+               else if(*bot==-1)
+                       *++bot |= 0xc0000000;
+               else break;
+       }
+       if(bot==top) return(inewint(*bot));
+       result = p = newsdot();
+       protect(p);
+       p->s.I = *top--;
+       while(top >= bot) {
+               p = p->s.CDR = newdot();
+               p->s.I = *top--;
+       }
+       p->s.CDR = 0;
+       np--;
+       return(result);
+}
+
+#define MAXINT 0x80000000L
+
+Ihau(fix)
+register int fix;
+{
+       register count;
+       if(fix==MAXINT)
+               return(32);
+       if(fix < 0)
+               fix = -fix;
+       for(count = 0; fix; count++)
+               fix /= 2;
+       return(count);
+}
+lispval
+Lhau()
+{
+       register count;
+       register lispval handy;
+       register dum1,dum2;
+       lispval Labsval();
+
+       handy = lbot->val;
+top:
+       switch(TYPE(handy)) {
+       case INT:
+               count = Ihau(handy->i);
+               break;
+       case SDOT:
+               handy = Labsval();
+               for(count = 0; handy->s.CDR!=((lispval) 0); handy = handy->s.CDR)
+                       count += 30;
+               count += Ihau(handy->s.I);
+               break;
+       default:
+               handy = errorh1(Vermisc,"Haulong: bad argument",nil,
+                              TRUE,997,handy);
+               goto top;
+       }
+       return(inewint(count));
+}
+lispval
+Lhaipar()
+{
+       int *sp();
+       register lispval work;
+       register n;
+       register int *top = sp() - 1;
+       register int *bot;
+       int mylen;
+
+       /*chkarg(2);*/
+       work = lbot->val;
+                                       /* copy data onto stack */
+on1:
+       switch(TYPE(work)) {
+       case INT:
+               stack(work->i);
+               break;
+       case SDOT:
+               for(; work!=((lispval) 0); work = work->s.CDR)
+                       stack(work->s.I);
+               break;
+       default:
+               work = errorh1(Vermisc,"Haipart: bad first argument",nil,
+                               TRUE,996,work);
+               goto on1;
+       }
+       bot = sp();
+       if(*bot < 0) {
+               stack(0);
+               dsmult(top,bot,-1);
+               bot--;
+       }
+       for(; *bot==0 && bot < top; bot++);
+                               /* recalculate haulong internally */
+       mylen = (top - bot) * 30 + Ihau(*bot);
+                               /* get second argument            */
+       work = lbot[1].val;
+       while(TYPE(work)!=INT)
+               work = errorh1(Vermisc,"Haipart: 2nd arg not int",nil,
+                               TRUE,995,work);
+       n = work->i;
+       if(n >= mylen || -n >= mylen)
+               goto done;
+       if(n==0) return(inewint(0));
+       if(n > 0) {
+                               /* Here we want n most significant bits
+                                  so chop off mylen - n bits */
+               stack(0);
+               n = mylen - n;
+               for(n; n >= 30; n -= 30)
+                       top--;
+               if(top < bot)
+                       error("Internal error in haipart #1",FALSE);
+               dsdiv(top,bot,1<<n);
+
+       } else {
+                               /* here we want abs(n) low order bits */
+               stack(0);
+               bot = top + 1;
+               for(; n <= 0; n += 30)
+                       bot--;
+               n = 30 - n;
+               *bot &= ~ (-1<<n);
+       }
+done:
+       return(export(top + 1,bot));
+}
+#define STICKY 1
+#define TOEVEN 2
+lispval
+Ibiglsh(bignum,count,mode)
+lispval bignum, count;
+{
+       int *sp();
+       register lispval work;
+       register n;
+       register int *top = sp() - 1;
+       register int *bot;
+       int mylen, guard = 0, sticky = 0, round = 0;
+       lispval export();
+
+                               /* get second argument            */
+       work = count;
+       while(TYPE(work)!=INT)
+               work = errorh1(Vermisc,"Bignum-shift: 2nd arg not int",nil,
+                               TRUE,995,work);
+       n = work->i;
+       if(n==0) return(bignum);
+       for(; n >= 30; n -= 30) {/* Here we want to multiply by 2^n
+                                  so start by copying n/30 zeroes
+                                  onto stack */
+               stack(0);
+       }
+
+       work = bignum;          /* copy data onto stack */
+on1:
+       switch(TYPE(work)) {
+       case INT:
+               stack(work->i);
+               break;
+       case SDOT:
+               for(; work!=((lispval) 0); work = work->s.CDR)
+                       stack(work->s.I);
+               break;
+       default:
+               work = errorh1(Vermisc,"Bignum-shift: bad bignum argument",nil,
+                               TRUE,996,work);
+               goto on1;
+       }
+       bot = sp();
+       if(n >= 0) {
+               stack(0);
+               bot--;
+               dsmult(top,bot,1<<n);
+       } else {
+                       /* Trimming will only work without leading
+                          zeroes without my having to think
+                          a lot harder about it, if the inputs
+                          are canonical */
+               for(n = -n; n > 30; n -= 30) {
+                       if(guard) sticky |= 1;
+                       guard = round;
+                       if(top > bot) {
+                               round = *top;
+                               top --;
+                       } else  {
+                               round = *top;
+                               *top >>= 30;
+                       }
+               }
+               if(n > 0) {
+                       if(guard) sticky |= 1;
+                       guard = round;
+                       round = dsrsh(top,bot,-n,-1<<n);
+               }
+               stack(0); /*so that dsadd1 will work;*/
+               if (mode==STICKY) {
+                       if(((*top&1)==0) && (round | guard | sticky))
+                               dsadd1(top,bot);
+               } else if (mode==TOEVEN) {
+                       int mask;
+
+                       if(n==0) n = 30;
+                       mask = (1<<(n-1));
+                       if(! (round & mask) ) goto chop;
+                       mask -= 1;
+                       if(  ((round&mask)==0)
+                         && guard==0
+                         && sticky==0
+                         && (*top&1)==0 ) goto chop;
+                       dsadd1(top,bot);
+               }
+               chop:;
+       }
+       work = export(top + 1,bot);
+       return(work);
+}
+
+/*From drb  Mon Jul 27 01:25:56 1981
+To: sklower
+
+The idea is that the answer/2
+is equal to the exact answer/2 rounded towards - infinity.  The final bit
+of the answer is the "or" of the true final bit, together with all true
+bits after the binary point.  In other words, the 1's bit of the answer
+is almost always 1.  THE FINAL BIT OF THE ANSWER IS 0 IFF n*2^i = THE
+ANSWER RETURNED EXACTLY, WITH A 0 FINAL BIT.
+
+
+To try again, more succintly:  the answer is correct to within 1, and
+the 1's bit of the answer will be 0 only if the answer is exactly
+correct. */
+
+lispval
+Lsbiglsh()
+{
+       register struct argent *mylbot = lbot;
+       chkarg(2,"sticky-bignum-leftshift");
+       return(Ibiglsh(lbot->val,lbot[1].val,STICKY));
+}
+lispval
+Lbiglsh()
+{
+       register struct argent *mylbot = lbot;
+       chkarg(2,"bignum-leftshift");
+       return(Ibiglsh(lbot->val,lbot[1].val,TOEVEN));
+}
+lispval
+HackHex() /* this is a one minute function so drb and kls can debug biglsh */
+/* (HackHex i) returns a string which is the result of printing i in hex */
+{
+       register struct argent *mylbot = lbot;
+       char buf[32];
+       sprintf(buf,"%lx",lbot->val->i);
+       return((lispval)inewstr(buf));
+}
diff --git a/usr/src/ucb/lisp/franz/error.c b/usr/src/ucb/lisp/franz/error.c
new file mode 100644 (file)
index 0000000..7f7005d
--- /dev/null
@@ -0,0 +1,439 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: error.c,v 1.5 83/09/12 14:17:50 sklower Exp $";
+#endif
+
+/*                                     -[Sun Sep  4 09:06:21 1983 by jkf]-
+ *     error.c                         $Locker:  $
+ * error handler
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+#include "frame.h"
+#include "catchfram.h"
+
+static lispval IEargs[5];
+static int     IElimit;
+
+/* error
+ * this routine is always called on a non-fatal error.  The first argu-
+ * ment is printed out.  The second a boolean flag indicating if the
+ * error routine is permitted to return a pointer to a lisp value if
+ * the "cont" command is executed.
+ */
+/* error from lisp C code, this temporarily replaces the old error
+ * allowing us to interface with the new errset scheme with minimum
+ * difficulty.  We assume that an error which comes to this routine
+ * is of an "undefined error type" ER%misc .  Soon all calls to this
+ * routine will be removed.
+ *
+ */
+
+lispval
+error(mesg,contvl)
+char *mesg;
+int contvl;
+{
+    lispval errorh();
+
+    return(errorh(Vermisc,mesg,nil,contvl,0));
+}
+
+
+/* new error handler, works with errset 
+ * 
+ * call is errorh(type,message,valret,contuab) where
+ * type is an atom which classifys the error, and whose clb, if not nil
+ * is the name of a function to call to handle the error.
+ * message is a character string to print to describe the error
+ * valret is the value to return to an errset if one is found,
+ * and contuab is non nil if this error is continuable.
+ */
+
+/* VARARGS5 */
+static lispval
+Ierrorh(type,message,valret,contuab,uniqid)
+lispval type,valret;
+int uniqid,contuab;
+char *message;
+{
+       register struct frame *curp, *uwpframe = (struct frame *)0; 
+       register lispval handy;
+       lispval *work = IEargs; 
+       int limit = IElimit;
+       int pass, curdepth;
+       lispval Lread(), calhan();
+       lispval contatm;
+       lispval handy2;
+       extern struct frame *errp;
+       pbuf pb;
+       Savestack(2);
+
+       contatm = (contuab == TRUE ? tatom : nil);
+
+       /* if there is a catch every error handler */
+       if((handy = Verall->a.clb) != nil)      
+       {
+           handy = Verall->a.clb;
+           Verall->a.clb = nil;                /* turn off before calling */
+           handy = calhan(limit,work,type,uniqid,contatm,message,handy);
+           if(contuab && (TYPE(handy) == DTPR))
+               return(handy->d.car);
+       }
+
+       if((handy = type->a.clb) != nil)        /* if there is an error handler */
+       {
+           handy = calhan(limit,work,type,uniqid,contatm,message,handy);
+           if(contuab && (TYPE(handy) == DTPR))
+               return(handy->d.car);
+       }
+
+       pass = 1;
+       /* search stack for error catcher */
+  ps2:
+
+       for (curp = errp ; curp != (struct frame *) 0 ; curp = curp->olderrp)
+       {
+          if(curp->class == F_CATCH) 
+          {
+               /* 
+                * interesting catch tags are ER%unwind-protect, generated
+                * by unwind-protect and ER%all, generated by errset
+                */
+               if((pass == 1) && (curp->larg1 == Veruwpt))
+               {
+                   uwpframe = curp;
+                   pass = 2;
+                   goto ps2;
+               }
+               else if(curp->larg1 == Verall)
+               {
+                   /* 
+                    * have found an errset to jump to. If there is an
+                    * errset handler, first call that.
+                    */
+                   if((handy=Verrset->a.clb) != nil)
+                   {
+                       calhan(limit,work,type,uniqid,contatm,message,handy);
+                   }
+
+                   /*
+                    * if there is an unwind-protect then go to that first.
+                    * The unwind protect will return to errorh after
+                    * it has processed its cleanup forms.
+                    * assert: if pass == 2 
+                    *          then there is a pending unwind-protect
+                    */
+                    if(uwpframe != (struct frame *)0)
+                    {
+                       /*
+                        * generate form to return to unwind-protect 
+                        */
+                       protect(handy2 = newdot());
+                       handy2->d.car = Veruwpt;
+                       handy = handy2->d.cdr = newdot();
+                       handy->d.car = nil;             /* indicates error */
+                       handy = handy->d.cdr = newdot();
+                       handy->d.car = type;
+                       handy = handy->d.cdr = newdot();
+                       handy->d.car = matom(message);
+                       handy = handy->d.cdr = newdot();
+                       handy->d.car = valret;
+                       handy = handy->d.cdr = newdot();
+                       handy->d.car = inewint(uniqid);
+                       handy = handy->d.cdr = newdot();
+                       handy->d.car = inewint(contuab);
+                       while (limit-- > 0)     /* put in optional args */
+                       {  handy = handy->d.cdr = newdot();
+                          handy->d.car = *work++;
+                       }
+                       lispretval = handy2;            /* return this as value */
+                       retval = C_THROW;
+                       Iretfromfr(uwpframe);
+                       /* NOTREACHED */
+                   }
+                   /*
+                    * Will return to errset
+                    * print message if flag on this frame is non nil
+                    */
+                   if(curp->larg2 != nil)
+                   {
+                       printf("%s  ",message);
+                       while(limit-->0) {
+                           printr(*work++,stdout);
+                           fflush(stdout);
+                       }
+                       fputc('\n',stdout);
+                       fflush(stdout);
+                   }
+
+                   lispretval = valret;
+                   retval = C_THROW;           /* looks like a throw */
+                   Iretfromfr(curp);
+               }
+           }
+       }
+           
+       /* no one will catch this error, we must see if there is an
+          error-goes-to-top-level catcher */
+       
+       if (Vertpl->a.clb != nil)
+       {
+           
+           handy = calhan(limit,work,type,uniqid,contatm,message,Vertpl->a.clb);
+           if( contuab  && (TYPE(handy) == DTPR))
+                  return(handy->d.car);
+       }
+
+       /* at this point, print error message and break, just like
+          the current error scheme */
+       printf("%s ",message);
+       while(limit-->0) {
+               printr(*work++,stdout);
+               fflush(stdout);
+       }
+
+
+       /* If automatic-reset is set
+        * we will now jump to top level, calling the reset function
+        * if it exists, or using the c rest function if it does not 
+        */
+
+       if(Sautor)
+       {
+               if ((handy = reseta->a.fnbnd) != nil)
+               {
+                       lispval Lapply();
+                       lbot = np;
+                       protect(reseta);
+                       protect(nil);
+                       Lapply();
+               }
+               Inonlocalgo(C_RESET,inewint(0),nil);
+               /* NOTREACHED */
+       }
+       
+       /*
+        * no one wants the error.  We set up another read-eval-print
+        * loop. The user can get out of this error by typing (return 'val)
+        * if the error is continuable.  Normally this code be replaced
+        * by more clever lisp code, when the full lisp is built
+        */
+
+       errp = Pushframe(F_PROG,nil,nil);
+
+       if(TYPE(Verdepth->a.clb) != INT)
+       {
+               curdepth = 1;
+       }
+       else curdepth = 1 + Verdepth->a.clb->i;
+       PUSHDOWN(Verdepth,inewint(curdepth));
+
+       switch(retval) {
+       case C_RET:     /* 
+                        * attempt to return from error
+                        */
+                       if(!contuab) error("Can't continue from this error",
+                                                 FALSE);
+                       popnames(errp->svbnp);
+                       errp = Popframe();
+                       Restorestack();
+                       return(lispretval);
+
+       case C_GO:      /*
+                        * this may look like a valid prog, but it really
+                        * isn't, since go's are not allowed.  Let the
+                        * user know.
+                        */
+                       error("Can't 'go' through an error break",FALSE);
+                       /* NOT REACHED */
+
+       case C_INITIAL: /*
+                         * normal case, just fall through into read-eval-print
+                         * loop
+                         */
+                       break;
+       }
+       lbot = np;
+       protect(P(stdin));
+       protect(eofa);
+
+       while(TRUE) {
+               
+               fprintf(stdout,"\n%d:>",curdepth);
+               dmpport(stdout);
+               vtemp = Lread();
+               if(vtemp == eofa) franzexit(0);
+               printr(eval(vtemp),stdout);
+       }
+       /* NOTREACHED */
+}
+
+lispval
+errorh(type,message,valret,contuab,uniqid)
+lispval type,valret;
+int uniqid,contuab;
+char *message;
+{
+       IElimit = 0;
+       Ierrorh(type,message,valret,contuab,uniqid);
+       /* NOTREACHED */
+}
+
+lispval
+errorh1(type,message,valret,contuab,uniqid,arg1)
+lispval type,valret,arg1;
+int uniqid,contuab;
+char *message;
+{
+       IElimit = 1;
+       IEargs[0] = arg1;
+       Ierrorh(type,message,valret,contuab,uniqid);
+       /* NOTREACHED */
+}
+
+lispval
+errorh2(type,message,valret,contuab,uniqid,arg1,arg2)
+lispval type,valret,arg1,arg2;
+int uniqid,contuab;
+char *message;
+{
+       IElimit = 2;
+       IEargs[0] = arg1;
+       IEargs[1] = arg2;
+       Ierrorh(type,message,valret,contuab,uniqid);
+       /* NOTREACHED */
+}
+
+lispval
+calhan(limit,work,type,uniqid,contuab,message,handler)
+register lispval *work;
+lispval handler,type,contuab;
+register limit;
+register char *message;
+int uniqid;
+{
+           register lispval handy;
+           Savestack(4);
+           lbot = np;
+           protect(handler);           /* funcall the handler */
+           protect(handy = newdot());          /* with a list consisting of */
+           handy->d.car = type;                        /* type, */
+           handy = (handy->d.cdr = newdot());
+           handy->d.car = inewint(uniqid);     /* identifying number, */
+           handy = (handy->d.cdr = newdot());
+           handy->d.car = contuab;
+           handy = (handy->d.cdr = newdot());
+           handy->d.car = matom(message);      /* message to be typed out, */
+           while(limit-- > 0)
+           {                                   /* any other args. */
+                   handy = handy->d.cdr = newdot();
+                   handy->d.car = *work++;
+           }
+           handy->d.cdr = nil;
+
+           handy = Lfuncal();
+           Restorestack();
+           return(handy);
+}
+
+/* lispend **************************************************************/
+/* Fatal errors come here, with their epitaph.                         */
+lispend(mesg)
+       char    mesg[];
+       {
+       dmpport(poport);
+       fprintf(errport,"%s\n",mesg);
+       dmpport(errport);
+       franzexit(0);
+       /* NOT REACHED */
+       }
+
+/* namerr ***************************************************************/
+/* handles namestack overflow, at present by simply giving a message   */
+
+namerr()
+{
+       if((nplim = np + NAMINC) > orgnp + NAMESIZE) 
+       {  
+         printf("Unrecoverable Namestack Overflow, (reset) is forced\n");
+         fflush(stdout);
+         nplim = orgnp + NAMESIZE - 4*NAMINC;
+         lbot = np = nplim - NAMINC;
+         protect(matom("reset"));
+         Lfuncal();
+       }
+       error("NAMESTACK OVERFLOW",FALSE);
+       /* NOT REACHED */
+}
+
+binderr()
+{
+       bnp -= 10;
+       error("Bindstack overflow.",FALSE);
+       /* NOT REACHED */
+}
+
+rtaberr()
+{
+       bindfix(Vreadtable,strtab,nil);
+       error("Illegal read table.",FALSE);
+       /* NOT REACHED */
+}
+xserr()
+{
+       error("Ran out of alternate stack",FALSE);
+}
+badmem(n)
+{
+       char errbuf[256], *sprintf();
+
+       sprintf(errbuf,"Attempt to allocate beyond static structures (%d).",n);
+       error(errbuf,FALSE);
+       /* NOT REACHED */
+}
+argerr(msg)
+char *msg;
+{
+       errorh1(Vermisc,"incorrect number of args to",
+                                 nil,FALSE,0,matom(msg));
+       /* NOT REACHED */
+}
+
+lispval Vinterrfcn = nil;
+
+/*
+ * wnaerr - wrong number of arguments to a compiled function hander
+ * called with the function name (symbol) and a descriptor of the
+ * number of arguments that were expected.  The form of the descriptor
+ * is (considered as a decimal number) xxyy where xx is the minumum
+ * and yy-1 is the maximum.  A maximum of -1 means that there is no
+ * maximum.
+ *
+ */
+wnaerr(fcn,wantargs)
+lispval fcn;
+{
+    if (Vinterrfcn == nil)
+    {
+       Vinterrfcn = matom("int:wrong-number-of-args-error");
+    }
+    if (Vinterrfcn->a.fnbnd != nil)
+    {
+       protect(fcn);
+       protect(inewint(wantargs / 1000));        /* min */
+       protect(inewint((wantargs % 1000) - 1));  /* max */
+       Ifuncal(Vinterrfcn);
+       error("wrong number of args function should never return ", FALSE);
+    }
+
+    errorh1(Vermisc,"wrong number of arguments to ",nil,FALSE,0,fcn);
+}
+
+       
+    
diff --git a/usr/src/ucb/lisp/franz/eval.c b/usr/src/ucb/lisp/franz/eval.c
new file mode 100644 (file)
index 0000000..1d62fcb
--- /dev/null
@@ -0,0 +1,807 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: eval.c,v 1.6 83/09/07 17:54:42 sklower Exp $";
+#endif
+
+/*                                     -[Thu Aug 18 10:07:22 1983 by jkf]-
+ *     eval.c                          $Locker:  $
+ * evaluator
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include <signal.h>
+#include "frame.h"
+
+
+
+/*
+ *     eval
+ * returns the value of the pointer passed as the argument.            
+ *
+ */
+
+lispval
+eval(actarg)
+lispval actarg;
+{
+#define argptr handy
+    register lispval a = actarg;
+    register lispval handy;
+    register struct nament *namptr;
+    register struct argent *workp;
+    struct nament *oldbnp = bnp;
+    int dopopframe = FALSE;
+    int type, shortcircuit = TRUE;
+    lispval Ifcall(), Iarray();
+    Savestack(4);
+
+    /*debugging 
+    if (rsetsw && rsetatom->a.clb != nil) {
+       printf("Eval:");
+       printr(a,stdout);
+       printf("\nrsetsw: %d evalhsw: %d\n", rsetsw, evalhsw);
+       printf("*rset: ");
+       printr(rsetatom->a.clb,stdout);
+       printf(" evalhook: ");
+       printr(evalhatom->a.clb,stdout);
+       printf(" evalhook call flag^G: %d\n", evalhcallsw);
+       fflush(stdout); 
+    };  
+    */
+
+    /* check if an interrupt is pending         and handle if so */
+    if(sigintcnt > 0) sigcall(SIGINT);
+
+    if (rsetsw && rsetatom->a.clb != nil)  /* if (*rset t) has been done */
+    {
+       pbuf pb;
+       shortcircuit = FALSE;
+       if (evalhsw != nil && evalhatom->a.clb != nil)
+       {
+                                               /*if (sstatus evalhook t)
+                                                   and evalhook non-nil */
+           if (!evalhcallsw)
+                       /*if we got here after calling evalhook, then
+                         evalhcallsw will be TRUE, so we want to skip calling
+                         the hook function, permitting one form to be
+                         evaluated before the hook fires.
+                        */
+           {
+               /* setup equivalent of (funcall evalhook <arg to eval>) */
+               (np++)->val = a;                /* push form on namestack */
+               lbot=np;                        /* set up args to funcall */
+               (np++)->val = evalhatom->a.clb; /* push evalhook's clb */
+               (np++)->val = a;                /* eval's arg becomes
+                                                  2nd arg to funcall */
+               PUSHDOWN(evalhatom, nil);       /* bind evalhook to nil*/
+               PUSHDOWN(funhatom, nil);        /* bind funcallhook to nil*/
+               funhcallsw = TRUE;              /* skip any funcall hook */
+               handy = Lfuncal();              /* now call funcall */
+               funhcallsw = FALSE;
+               POP;
+               POP;
+               Restorestack();
+               return(handy);
+           };
+       }
+       errp = Pushframe(F_EVAL,a,nil);
+       dopopframe = TRUE;      /* remember to pop later */
+       if(retval == C_FRETURN)
+       {
+           Restorestack();
+           errp = Popframe();
+           return(lispretval);
+       }
+    };
+        
+    evalhcallsw = FALSE;   /* clear indication that evalhook called */
+    
+    switch (TYPE(a))
+    {
+    case ATOM:
+       if (rsetsw && rsetatom->a.clb != nil && bptr_atom->a.clb != nil) {
+
+           struct nament *bpntr, *eval1bptr;
+                                 /* Both rsetsw and rsetatom for efficiency*/
+                                   /* bptr_atom set by second arg to eval1 */
+           eval1bptr = (struct nament *) bptr_atom->a.clb->d.cdr;
+                                   /* eval1bptr is bnp when eval1 was called;
+                                      if an atom was bound after this,
+                                      then its clb is valid */
+           for (bpntr = eval1bptr; bpntr < bnp; bpntr++)
+               if (bpntr->atm==a) {
+                   handy = a->a.clb;
+                   goto gotatom;
+               };                  /* Value saved in first binding of a,
+                                      if any, after pointer to eval1,
+                                      is the valid value, else use its clb */
+           for (bpntr = (struct nament *)bptr_atom->a.clb->d.car;
+             bpntr < eval1bptr; bpntr++)
+               if (bpntr->atm==a) {
+                   handy=bpntr->val;
+                   goto gotatom;   /* Simply no way around goto here */
+               };
+       };
+        handy = a->a.clb;
+    gotatom:
+        if(handy==CNIL) {
+            handy = errorh1(Vermisc,"Unbound Variable:",nil,TRUE,0,a);
+        }
+       if(dopopframe) errp = Popframe();
+       Restorestack();
+        return(handy);
+
+    case VALUE:
+       if(dopopframe) errp = Popframe();
+       Restorestack();
+        return(a->l);
+
+    case DTPR:
+        (np++)->val = a;               /* push form on namestack */
+        lbot = np;                     /* define beginning of argstack */
+        /* oldbnp = bnp;                  redundant - Mitch Marcus */
+        a = a->d.car;                  /* function name or lambda-expr */
+        for(EVER)
+            {
+            switch(TYPE(a))
+                {
+            case ATOM:
+                                       /*  get function binding  */
+                if(a->a.fnbnd==nil && a->a.clb!=nil) {
+                    a=a->a.clb;
+                    if(TYPE(a)==ATOM)
+                        a=a->a.fnbnd;
+                } else
+                    a = a->a.fnbnd;
+                break;
+            case VALUE:
+                a = a->l;              /*  get value  */
+                break;
+                }
+
+            vtemp = (CNIL-1);       /* sentinel value for error test */
+
+        /*funcal:*/    switch (TYPE(a))
+                {
+            case BCD:    /* function */
+                argptr = actarg->d.cdr;
+
+                                   /* decide whether lambda, nlambda or
+                                      macro and push args onto argstack
+                                      accordingly.                */
+
+                if(a->bcd.discipline==nlambda) {
+                    (np++)->val = argptr;
+                    TNP;
+                } else if(a->bcd.discipline==macro) {
+                    (np++)->val = actarg;
+                    TNP;
+                } else for(;argptr!=nil; argptr = argptr->d.cdr) {
+                   /* short circuit evaluations of ATOM, INT, DOUB
+                    * if not in debugging mode
+                    */
+                   if(shortcircuit
+                      && ((type = TYPE(argptr->d.car)) == ATOM)
+                      && (argptr->d.car->a.clb != CNIL))
+                       (np++)->val = argptr->d.car->a.clb;
+                   else if(shortcircuit &&
+                               ((type == INT) || (type == STRNG)))
+                       (np++)->val = argptr->d.car;
+                   else
+                       (np++)->val = eval(argptr->d.car);
+                    TNP;
+                }
+                /* go for it */
+
+                if(TYPE(a->bcd.discipline)==STRNG)
+                    vtemp = Ifcall(a);
+                else
+                    vtemp = (*(lispval (*)())(a->bcd.start))();
+                break;
+
+            case ARRAY:
+                vtemp = Iarray(a,actarg->d.cdr,TRUE);
+                break;
+
+            case DTPR:             /* push args on argstack according to
+                                      type                */
+               protect(a);     /* save function definition in case function
+                                  is redefined */
+               lbot = np;
+                argptr = a->d.car;
+                if (argptr==lambda) {
+                    for(argptr = actarg->d.cdr;
+                        argptr!=nil; argptr=argptr->d.cdr) {
+                        
+                        (np++)->val = eval(argptr->d.car);
+                        TNP;
+                    }
+                } else if (argptr==nlambda) {
+                    (np++)->val = actarg->d.cdr;
+                    TNP;
+                } else if (argptr==macro) {
+                    (np++)->val = actarg;
+                    TNP;
+                } else if (argptr==lexpr) {
+                    for(argptr = actarg->d.cdr;
+                      argptr!=nil; argptr=argptr->d.cdr) {
+                        
+                        (np++)->val = eval(argptr->d.car);
+                        TNP;
+                    }
+                    handy = newdot();
+                    handy->d.car = (lispval)lbot;
+                    handy->d.cdr = (lispval)np;
+                    PUSHDOWN(lexpr_atom,handy);
+                    lbot = np;
+                    (np++)->val = inewint(((lispval *)handy->d.cdr) - (lispval *)handy->d.car);
+
+                } else break;    /* something is wrong - this isn't a proper function */
+
+                argptr = (a->d.cdr)->d.car;
+                namptr =  bnp;
+                workp = lbot;
+                if(bnp + (np - lbot)> bnplim)
+                    binderr();
+                for(;argptr != (lispval)nil;
+                     workp++,argptr = argptr->d.cdr)    /* rebind formal names (shallow) */
+                {
+                    if(argptr->d.car==nil)
+                        continue;
+                    /*if(((namptr)->atm = argptr->d.car)==nil)
+                        error("Attempt to lambda bind nil",FALSE);*/
+                    namptr->atm = argptr->d.car;
+                    if (workp < np) {
+                        namptr->val = namptr->atm->a.clb;
+                        namptr->atm->a.clb = workp->val;
+                    } else
+                        bnp = namptr,
+                        error("Too few actual parameters",FALSE);
+                    namptr++;
+                }
+                bnp = namptr;
+                if (workp < np)
+                    error("Too many actual parameters",FALSE);
+
+                                   /* execute body, implied prog allowed */
+
+                for (handy = a->d.cdr->d.cdr;
+                    handy != nil;
+                    handy = handy->d.cdr) {
+                        vtemp = eval(handy->d.car);
+                    }
+                }
+            if (vtemp != (CNIL-1)) {
+                               /* if we get here with a believable value, */
+                               /* we must have executed a function. */
+                popnames(oldbnp);
+
+                /* in case some clown trashed t */
+
+                tatom->a.clb = (lispval) tatom;
+                if(a->d.car==macro)
+               {
+                   if(Vdisplacemacros->a.clb && (TYPE(vtemp) == DTPR))
+                   {
+                       actarg->d.car = vtemp->d.car;
+                       actarg->d.cdr = vtemp->d.cdr;
+                   }
+                   vtemp = eval(vtemp);
+               }
+                    /* It is of the most wonderful 
+                       coincidence that the offset
+                       for car is the same as for
+                       discipline so we get bcd macros
+                       for free here ! */
+               if(dopopframe) errp = Popframe();
+               Restorestack();
+               return(vtemp);
+           }
+            popnames(oldbnp);
+            a = (lispval) errorh1(Verundef,"eval: Undefined function ",nil,TRUE,0,actarg->d.car);
+            }
+
+        }
+    if(dopopframe) errp = Popframe();
+    Restorestack();
+    return(a);    /* other data types are considered constants */
+}
+
+/*
+ *    popnames
+ * removes from the name stack all entries above the first argument.   
+ * routine should usually be used to clean up the name stack as it    
+ * knows about the special cases.  bnp is returned pointing to the
+ * same place as the argument passed.
+ */
+lispval
+popnames(llimit)
+register struct nament *llimit;
+{
+    register struct nament *rnp;
+
+    for(rnp = bnp; --rnp >= llimit;)
+        rnp->atm->a.clb = rnp->val;
+    bnp = llimit;
+}
+
+
+/* dumpnamestack
+ * utility routine to dump out the namestack.
+ * from bottom to 5 above np
+ * should be put elsewhere
+ */
+dumpnamestack()
+{
+    struct argent *newnp;
+
+    printf("namestack dump:\n");
+    for(newnp = orgnp ; (newnp < np + 6) && (newnp < nplim) ; newnp++)
+    {
+       if(newnp == np) printf("**np:**\n");
+       printf("[%d]: ",newnp-orgnp);
+       printr(newnp->val,stdout);
+       printf("\n");
+    }
+    printf("end namestack dump\n");
+}
+
+
+
+lispval
+Lapply()
+{
+    register lispval a;
+    register lispval handy;
+    lispval vtemp, Ifclosure();
+    struct nament *oldbnp = bnp;
+    struct argent *oldlbot = lbot; /* Bottom of my frame! */
+    struct argent *oldnp = np; /* First free on stack */
+    int extrapush;             /* if must save function value */
+
+    a = lbot->val;
+    argptr = lbot[1].val;
+    if(np-lbot!=2)
+        errorh2(Vermisc,"Apply: Wrong number of args.",nil,FALSE,
+               999,a,argptr);
+    if(TYPE(argptr)!=DTPR && argptr!=nil)
+        argptr = errorh1(Vermisc,"Apply: non-list of args",nil,TRUE,
+                998,argptr);
+    (np++)->val = a;    /* push form on namestack */
+    TNP;
+    lbot = np;        /* bottom of current frame */
+    for(EVER)
+        {
+       extrapush = 0;
+        if (TYPE(a) == ATOM) { a = a->a.fnbnd; extrapush = 1; }
+                                       /* get function definition (unless
+                                          calling form is itself a lambda-
+                                          expression) */
+        vtemp = CNIL;                  /* sentinel value for error test */
+        switch (TYPE(a)) {
+
+        case BCD: 
+                                       /* push arguments - value of a */
+            if(a->bcd.discipline==nlambda || a->bcd.discipline==macro) {
+                (np++)->val=argptr;
+                TNP;
+            } else for (; argptr!=nil; argptr = argptr->d.cdr) {
+                (np++)->val=argptr->d.car;
+                TNP;
+            }
+
+           if(TYPE(a->bcd.discipline) == STRNG)
+             vtemp = Ifcall(a);        /* foreign function */
+           else
+              vtemp = (*(lispval (*)())(a->bcd.start))(); /* go for it */
+            break;
+
+        case ARRAY:
+            vtemp = Iarray(a,argptr,FALSE);
+            break;
+
+
+        case DTPR:
+            if (a->d.car==nlambda || a->d.car==macro) {
+                (np++)->val = argptr;
+                TNP;
+            } else if (a->d.car==lambda)
+                for (; argptr!=nil; argptr = argptr->d.cdr) {
+                    (np++)->val = argptr->d.car;
+                    TNP;
+                }
+            else if(a->d.car==lexpr) {
+                for (; argptr!=nil; argptr = argptr->d.cdr) {
+                    
+                    (np++)->val = argptr->d.car;
+                    TNP;
+                }
+                handy = newdot();
+                handy->d.car = (lispval)lbot;
+                handy->d.cdr = (lispval)np;
+                PUSHDOWN(lexpr_atom,handy);
+                lbot = np;
+                (np++)->val = inewint(((lispval *)handy->d.cdr) - (lispval *)handy->d.car);
+
+            } else break;    /* something is wrong - this isnt a proper function */
+            rebind(a->d.cdr->d.car,lbot);
+
+           if (extrapush == 1) { protect(a); extrapush = 2;}
+            for (handy = a->d.cdr->d.cdr;
+                handy != nil;
+                handy = handy->d.cdr) {
+                    vtemp = eval(handy->d.car);    /* go for it */
+                }
+           break;
+           
+       case VECTOR:
+           /* certain vectors are valid (fclosures) */
+          if(a->v.vector[VPropOff] == fclosure)
+              vtemp = (lispval) Ifclosure(a,FALSE);
+          break;
+               
+        };
+       
+       /* pop off extra value if we pushed it before */
+       if (extrapush == 2)
+       {
+           np--;
+           extrapush = 0;
+       };
+       
+        if (vtemp != CNIL)
+                               /* if we get here with a believable value, */
+                               /* we must have executed a function. */
+            {
+            popnames(oldbnp);
+
+            /* in case some clown trashed t */
+
+            tatom->a.clb = (lispval) tatom;
+           np = oldnp; lbot = oldlbot;
+            return(vtemp);
+            }
+        popnames(oldbnp);
+        a = (lispval) errorh1(Verundef,"apply: Undefined Function ",
+                                             nil,TRUE,0,oldlbot->val);
+    }
+    /*NOT REACHED*/
+}
+
+
+/*
+ * Rebind -- rebind formal names
+ */
+rebind(argptr,workp)
+register lispval argptr;        /* argptr points to list of atoms */
+register struct argent * workp;        /* workp points to position on stack
+                       where evaluated args begin */
+{
+    register struct nament *namptr = bnp;
+
+    for(;argptr != (lispval)nil;
+         workp++,argptr = argptr->d.cdr)  /* rebind formal names (shallow) */
+    {
+        if(argptr->d.car==nil)
+            continue;
+        namptr->atm = argptr->d.car;
+        if (workp < np) {
+            namptr->val = namptr->atm->a.clb;
+            namptr->atm->a.clb = workp->val;
+        } else
+            bnp = namptr,
+            error("Too few actual parameters",FALSE);
+        namptr++;
+        if(namptr > bnplim)
+            binderr();
+    }
+    bnp = namptr;
+    if (workp < np)
+        error("Too many actual parameters",FALSE);
+}
+
+/* the argument to Lfuncal is now mandatory since nargs
+ * wont work on RISC. If it is given  then it is 
+ * the name of the function to call and lbot points to the first arg.
+ * if it is not given, then lbot points to the function to call
+ */
+lispval
+Ifuncal(fcn)
+lispval fcn;
+{
+    register lispval a;
+    register lispval handy; 
+    struct nament *oldbnp = bnp;       /* MUST be first local for evalframe */
+    lispval fcncalled;
+    lispval Ifcall(),Llist(),Iarray(), Ifclosure();
+    lispval vtemp;
+    int typ, dopopframe = FALSE, extrapush;
+    extern lispval end[];
+    Savestack(3);
+
+    /*if(nargs()==1)                   /* function I am evaling.    */
+       a = fcncalled = fcn;
+    /*else { a = fcncalled = lbot->val; lbot++; }*/
+
+    /*debugging 
+    if (rsetsw && rsetatom->a.clb != nil) {
+       printf("funcall:");
+       printr(a,stdout);
+       printf("\nrsetsw: %d evalhsw: %d\n", rsetsw, evalhsw);
+       printf("*rset: ");
+       printr(rsetatom->a.clb,stdout);
+       printf(" funhook: ");
+       printr(funhatom->a.clb,stdout);
+       printf(" funhook call flag^G: %d\n",funhcallsw);
+       fflush(stdout); 
+    };  
+    */
+
+    /* check if exception pending */
+    if(sigintcnt > 0 ) sigcall(SIGINT);
+
+    if (rsetsw && rsetatom->a.clb != nil)  /* if (*rset t) has been done */
+    {          
+       pbuf pb;
+       if (evalhsw != nil && funhatom->a.clb != nil)
+       {
+                                               /*if (sstatus evalhook t)
+                                                   and evalhook non-nil */
+           if (!funhcallsw)
+                       /*if we got here after calling funcallhook, then
+                         funhcallsw will be TRUE, so we want to skip calling
+                         the hook function, permitting one form to be
+                         evaluated before the hook fires.
+                        */
+           {
+               /* setup equivalent of (funcall funcallhook <args to eval>) */
+               protect(a);
+               a = fcncalled = funhatom->a.clb; /* new function to funcall */
+               PUSHDOWN(funhatom, nil);        /* lambda-bind 
+                                                * funcallhook to nil
+                                                */
+               PUSHDOWN(evalhatom, nil);       
+            /* printf(" now will funcall ");
+               printr(a,stdout);
+               putchar('\n');
+               fflush(stdout); */
+           };
+       }
+       errp = Pushframe(F_FUNCALL,a,nil);
+       dopopframe = TRUE;      /* remember to pop later */
+       if(retval == C_FRETURN)
+       {
+           popnames(oldbnp);
+           errp = Popframe();
+           Restorestack();
+           return(lispretval);
+       }
+    };
+    
+    funhcallsw = FALSE;        /* so recursive calls to funcall will cause hook
+                          to fire */
+    for(EVER)
+    {
+     top:
+        extrapush = 0;
+       
+        typ = TYPE(a);
+        if (typ == ATOM)
+       {   /* get function defn (unless calling form */
+            /* is itself a lambda-expr) */
+           a = a->a.fnbnd;
+           typ = TYPE(a);
+           extrapush = 1;      /* must protect this later */
+       }
+        vtemp = CNIL-1;            /* sentinel value for error test */
+        switch (typ) {
+        case ARRAY:
+           protect(a);                 /* stack array descriptor on top */
+           a = a->ar.accfun;           /* now funcall access function */
+           goto top;
+        case BCD:
+            if(a->bcd.discipline==nlambda)
+                {   if(np==lbot) protect(nil);  /* default is nil */
+                while(np-lbot!=1 || (lbot->val != nil &&
+                      TYPE(lbot->val)!=DTPR)) {
+
+                           lbot->val = errorh1(Vermisc,"Bad funcall arg(s) to fexpr.",
+                                                nil,TRUE,0,lbot->val);
+                           
+                    np = lbot+1;
+                    }
+                }
+            /* go for it */
+
+            if(TYPE(a->bcd.discipline)==STRNG)
+                vtemp = Ifcall(a);
+            else
+                vtemp = (*(lispval (*)())(a->bcd.start))();
+            if(a->bcd.discipline==macro)
+                vtemp = eval(vtemp);
+            break;
+
+
+        case DTPR:
+            if (a->d.car == lambda) {
+                ;/* VOID */
+            } else if (a->d.car == nlambda || a->d.car==macro) {
+                if( np==lbot ) protect(nil);    /* default */
+                while(np-lbot!=1 || (lbot->val != nil &&
+                          TYPE(lbot->val)!=DTPR)) {
+                    lbot->val = error("Bad funcall arg(s) to fexpr.",TRUE);
+                    np = lbot+1;
+                    }
+            } else if (a->d.car == lexpr) {
+                handy = newdot();
+                handy->d.car = (lispval) lbot;
+                handy->d.cdr = (lispval) np;
+                PUSHDOWN(lexpr_atom,handy);
+                lbot = np;
+                (np++)->val = inewint(((lispval *)handy->d.cdr) - (lispval *)handy->d.car);
+            } else break;        /* something is wrong - this isn't a proper function */
+            rebind(a->d.cdr->d.car,lbot);
+
+           /* since the actual arguments are bound to their formal params
+            * we can pop them off the stack.  However if we are doing
+            * debugging (that is if we've pushed a frame on the stack)
+            * then we must not pop off the actual args since they must
+            * be visible for evalframe to work
+            */
+            if(!dopopframe) np = lbot;
+           if (extrapush == 1) {protect(a);  extrapush = 2;}
+            for (handy = a->d.cdr->d.cdr;
+                handy != nil;
+                handy = handy->d.cdr) {
+                    vtemp = eval(handy->d.car);    /* go for it */
+                }
+            if(a->d.car==macro)
+                vtemp = eval(vtemp);
+           break;
+           
+       case VECTOR:
+          /* A fclosure represented as a vector with the property 'fclosure' */
+          if(a->v.vector[VPropOff] == fclosure)
+              vtemp = (lispval) Ifclosure(a,TRUE);
+          break;
+          
+        }
+       
+       /* pop off extra value if we pushed it before */
+       if(extrapush == 2) { np-- ; extrapush = 0; }
+       
+        if (vtemp != CNIL-1)
+            /* if we get here with a believable value, */
+            /* we must have executed a function. */
+            {
+            popnames(oldbnp);
+
+            /* in case some clown trashed t */
+
+            tatom->a.clb = (lispval) tatom;
+
+           if(dopopframe) errp = Popframe();
+           Restorestack();
+            return(vtemp);
+            }
+        popnames(oldbnp);
+           a = fcncalled = (lispval) errorh1(Verundef,"funcall: Bad function",
+                                              nil,TRUE,0,fcncalled);
+    }
+    /*NOT REACHED*/
+}
+lispval   /* this version called from lisp */
+Lfuncal()
+{
+       lispval handy;
+       Savestack(0);
+       
+       switch(np-lbot)
+       {
+           case 0: argerr("funcall");
+                   break;
+       }
+       handy = lbot++->val;
+       handy = Ifuncal(handy);
+       Restorestack();
+       return(handy);
+}
+
+/* The following must be the next "function" after Lfuncal, for the
+sake of Levalf.  */
+fchack () {}
+
+
+/*
+ * Llexfun  :: lisp function lexpr-funcall
+ * lexpr-funcall is a cross between funcall and apply.
+ * the last argument is nil or a list of the rest of the arguments.
+ * we push those arguments on the stack and call funcall
+ *
+ */
+lispval
+Llexfun()
+{
+    register lispval handy;
+    
+    switch(np-lbot)
+    {
+       case 0: argerr("lexpr-funcall");        /* need at least one arg */
+               break;
+       case 1: return(Lfuncal());       /* no args besides function */
+    }
+    /* have at least one argument past the function to funcall */
+    handy = np[-1].val;                /* get last value */
+    np--;                      /* pop it off stack */
+    
+    while((handy != nil) && (TYPE(handy) != DTPR))
+       handy = errorh1(Vermisc,"lexpr-funcall: last argument is not a list ",
+                       nil,TRUE,0,handy);
+
+    /* stack arguments */
+    for( ; handy != nil ; handy = handy->d.cdr) protect(handy->d.car);
+
+    return(Lfuncal());
+}
+
+       
+#undef protect
+       
+/* protect 
+ * pushes the first argument onto namestack, thereby protecting from gc
+ */
+lispval
+protect(a)
+lispval a;
+{
+    (np++)->val = a;
+       if (np >=  nplim)
+        namerr();
+}
+
+/* unprot
+ * returns the top thing on the name stack.  Underflow had better not
+ * occur.
+ */
+lispval
+unprot()
+    {
+    return((--np)->val);
+    }
+
+lispval
+linterp()
+    {
+    error("BYTE INTERPRETER CALLED ERRONEOUSLY",FALSE);
+    }
+
+/* Undeff - called from qfuncl when it detects a call to a undefined
+    function from compiled code, we print out a message and
+    will continue only if returned a symbol (ATOM in C parlance).
+*/
+lispval
+Undeff(atmn)
+lispval atmn;
+{
+    do {atmn =errorh1(Verundef,"Undefined function called from compiled code ",
+                                     nil,TRUE,0,atmn);}
+       while(TYPE(atmn) != ATOM);
+    return(atmn);                    
+}
+
+/* VARARGS1 */
+bindfix(firstarg)
+lispval firstarg;
+{
+    register lispval *argp = &firstarg;
+    register struct nament *mybnp = bnp;
+    while(*argp != nil) {
+        mybnp->atm = *argp++;
+        mybnp->val = mybnp->atm->a.clb;
+        mybnp->atm->a.clb = *argp++;
+        bnp = mybnp++;
+    }
+}
+
diff --git a/usr/src/ucb/lisp/franz/eval2.c b/usr/src/ucb/lisp/franz/eval2.c
new file mode 100644 (file)
index 0000000..054be89
--- /dev/null
@@ -0,0 +1,516 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: eval2.c,v 1.6 83/09/12 14:18:02 sklower Exp $";
+#endif
+
+/*                                     -[Sat May  7 23:38:37 1983 by jkf]-
+ *     eval2.c                         $Locker:  $
+ * more of the evaluator
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+#include "frame.h"
+
+/* Iarray - handle array call.
+ *  fun - array object
+ *  args - arguments to the array call , most likely subscripts.
+ *  evalp - flag, if TRUE then the arguments should be evaluated when they
+ *     are stacked.
+ */
+lispval
+Iarray(fun,args,evalp)
+register lispval fun,args;
+{
+       Savestack(2);
+       
+       lbot = np;
+       protect(fun->ar.accfun);
+       for ( ; args != nil ; args = args->d.cdr)  /* stack subscripts */
+         if(evalp) protect(eval(args->d.car));
+         else protect(args->d.car);
+       protect(fun);
+       vtemp = Lfuncal();
+       Restorestack();
+       return(vtemp);
+}
+
+    
+dumpmydata(thing)
+int thing;
+{
+       register int *ip = &thing;
+       register int *lim = ip + nargs();
+
+       printf("Dumpdata got %d args:\n",nargs());
+       while(ip < lim) printf("%x\n",*ip++);
+       return(0);
+}
+/* Ifcall :: call foreign function/subroutine
+ *   Ifcall is handed a binary object which is the function to call.
+ * This function has already been determined to be a foreign function
+ * by noticing that its discipline field is a string.  
+ * The arguments to pass have already been evaluated and stacked.  We
+ * create on the stack a 'callg' type argument list to give to the 
+ * function.  What is passed to the foreign function depends on the
+ * type of argument.  Certain args are passes directly, others must be
+ * copied since the foreign function my want to change them.
+ * When the foreign function returns, we may have to box the result,
+ * depending on the type of foreign function.
+ */
+lispval
+Ifcall(a)
+lispval a;
+{
+       char *alloca();
+       long callg_();
+       register int *arglist;
+       register int index;
+       register struct argent *mynp;
+       register lispval ltemp;
+       pbuf pb;
+       int nargs = np - lbot, kind, mysize, *ap;
+       Keepxs();
+
+       /* put a frame on the stack which will save np and lbot in a
+          easy to find place in a standard way */
+       errp = Pushframe(F_TO_FORT,nil,nil);
+       mynp = lbot;
+       kind = (((char *)a->bcd.discipline)[0]);
+
+       /* dispatch according to whether call by reference or value semantics */
+       switch(kind) {
+       case 'f': case 'i': case 's': case 'r':
+               arglist = (int *) alloca((nargs + 1) * sizeof(int));
+               *arglist = nargs;
+               for(index = 1; index <=  nargs; index++) {
+                       switch(TYPE(ltemp=mynp->val)) {
+                               /* fixnums and flonums must be reboxed */
+                       case INT:
+                               stack(0);
+                               arglist[index] = (int) sp();
+                               *(int *) arglist[index] = ltemp->i;
+                               break;
+                       case DOUB:
+                               stack(0);
+                               stack(0);
+                               arglist[index] = (int) sp();
+                               *(double *) arglist[index] = ltemp->r;
+                               break;
+
+                               /* these cause only part of the structure to be sent */
+
+                       case ARRAY:
+                               arglist[index] = (int) ltemp->ar.data;
+                               break;
+
+
+                       case BCD:
+                               arglist[index] = (int) ltemp->bcd.start;
+                               break;
+
+                               /* anything else should be sent directly */
+
+                       default:
+                               arglist[index] = (int) ltemp;
+                               break;
+                       }
+                       mynp++;
+               }
+               break;
+       case 'v':
+               while(TYPE(mynp->val)!=VECTORI)
+                       mynp->val = error(
+"First arg to c-function-returning-vector must be of type vector-immediate",
+                                         TRUE);
+               nargs--;
+               mynp++;
+               lbot++;
+       case 'c': case 'd':
+               /* make one pass over args 
+               calculating size of arglist */
+               while(mynp < np) switch(TYPE(ltemp=mynp++->val)) {
+               case DOUB:
+                       nargs += ((sizeof(double)/sizeof(int))-1);
+                       break;
+               case VECTORI:
+                       if(ltemp->v.vector[-1]==Vpbv) {
+                           nargs += -1+VecTotSize(ltemp->vl.vectorl[-2]);
+                       }
+               }
+               arglist = (int *) alloca((nargs+1)*sizeof(int));
+               *arglist = nargs;
+               ap = arglist + 1;
+               /* make another pass over the args
+                  actually copying the arguments */
+               for(mynp = lbot; mynp < np; mynp++)
+                       switch(TYPE(ltemp=mynp->val)) {
+               case INT:
+                       *ap++ = ltemp->i;
+                       break;
+               case DOUB:
+                       *(double *)ap = ltemp->r;
+                       ap += (sizeof (double)) / (sizeof (long));
+                       break;
+               case VECTORI:
+                       if(ltemp->v.vector[-1]==Vpbv) {
+                               mysize = ltemp->vl.vectorl[-2];
+                               mysize = sizeof(long) * VecTotSize(mysize);
+                               bcopy(ap,ltemp,mysize);
+                               ap = (long *) (mysize + (int) ap);
+                               break;
+                       }
+               default:
+                       *ap++ = (long) ltemp;
+               }
+       }
+       switch(kind) {
+               case 'i': /* integer-function */
+               case 'c': /* C-function */
+                       ltemp = inewint(callg_(a->bcd.start,arglist));
+                       break;
+
+               case 'r': /* real-function*/
+               case 'd': /* C function declared returning double */
+                       {
+                       double result =
+                          (* ((double (*)()) callg_))(a->bcd.start,arglist);
+                       ltemp = newdoub();
+                       ltemp->r = result; 
+                       }
+                       break;
+
+               case 'f':  /* function */
+                       ltemp = (lispval) callg_(a->bcd.start,arglist);
+                       break;
+
+               case 'v': /* C function returning a structure */
+                       ap = (long *) callg_(a->bcd.start,arglist);
+                       ltemp = (--lbot)->val;
+                       mysize = ltemp->vl.vectorl[-2];
+                       mysize = sizeof(long) * VecTotSize(mysize);
+                       bcopy(ltemp,ap,mysize);
+                       break;
+
+               default:
+               case 's': /* subroutine */
+                       callg_(a->bcd.start,arglist);
+                       ltemp = tatom;
+       }
+       errp = Popframe();
+       Freexs();
+       return(ltemp);
+}
+
+bcopy(to,from,size)
+register char *to, *from;
+register size;
+{
+       while(--size >= 0) *to++ = *from++;
+}
+
+lispval
+ftolsp_(arg1)
+lispval arg1;
+{
+       int count; 
+       register lispval *ap = &arg1;
+       lispval save;
+       pbuf pb;
+       Savestack(1);
+
+       if((count = nargs())==0) return;;
+
+       if(errp->class==F_TO_FORT)
+               np = errp->svnp;
+       errp = Pushframe(F_TO_LISP,nil,nil);
+       lbot = np;
+       for(; count > 0; count--)
+               np++->val = *ap++;
+       save = Lfuncal();
+       errp = Popframe();
+       Restorestack();
+       return(save);
+}
+
+
+    
+/* Ifclosure :: evaluate a fclosure  (new version)
+ * the argument clos is a vector whose property is the atom fclosure
+ * the form of the vector is
+ *   0: function to run
+ * then for each symbol there is on vector entry containing a
+ * pointer to a sequence of two list cells of this form:
+ *     (name value . count)
+ * name is the symbol name to close over
+ * value is the saved value of the closure
+ *     (if the closure is 'active', the current value will be in the
+ *      symbol itself)
+ * count is a fixnum box (which can be destructively modified safely)
+ *  it is normally 0.  Each time the variable is put on the stack, it is
+ *  incremented.  It is decremented each time the the closure is left.
+ *  If the closure is invoked recusively without a rebinding of the
+ *  closure variable X, then the count will not be incremented.
+ *
+ * when entering a fclosure, for each variable there are three
+ * possibities:
+ *  (a) this is the first instance of this closed variable
+ *  (b) this is the second or greater recursive instance of
+ *      this closure variable, however it hasn't been normally lambda
+ *     bound since the last closure invocation
+ *  (c) like (b) but it has been lambda bound before the most recent
+ *     closure.
+ *
+ * case (a) can be determined by seeing if the count is 0.
+ * if the count is >0 then we must scan from the top of the stack down
+ * until we find either the closure or a lambda binding of the variable
+ * this determines whether it is case (b) or (c).
+ *
+ * There are three actions to perform in this routine:
+ * 1.  determine the closure type (a,b or c) and do any binding necessary
+ * 2.  call the closure function
+ * 3.  unbind any necessary closure variables.
+ *
+ * Now, the details of those actions:
+ * 1. for case (b), do nothing as we are still working with the correct
+ *    value
+ *    for case (a), pushdown the symbol and give it the value from
+ *     the closure, inc the closure count
+ *      push a closure marker on the bindstack too.
+ *    for case (c), must locate the correct value to set by searching
+ *      for the last lambda binding before the previous closure.
+ *      pushdown the symbol and that value, inc the closure count
+ *      push a closure marker on the bindstack too.
+ *    a closure marker has atom == int:closure-marker and value pointing
+ *      to the closure list.  This will be noticed when unbinding.
+ *
+ *  3. unbinding is just like popnames except if a closure marker is
+ *     seen, then this must be done:
+ *     if the count is 1, just store the symbol's value in the closure
+ *      and decrement the count.
+ *      if the count is >1, then search up the stack for the last
+ *      lambda before the next occurance of this closure variable
+ *      and set its value to the current value of the closure.
+ *      decrement the closure count.
+ *
+ * clos is the fclosure, funcallp is TRUE if this is called from funcall,
+ * otherwise it is called from apply
+ */
+
+#define Case_A 0
+#define Case_B 1
+#define Case_C 2
+
+lispval
+Ifclosure(clos,funcallp)
+register lispval clos;
+{
+    struct nament *oldbnp = bnp, *lbnp, *locatevar();
+    register int i;
+    register lispval vect;
+    int numvars, vlength, tcase, foundc;
+    lispval handy, atm_dtpr, value_dtpr, Ifuncal(), Lapply();
+    Savestack(3);
+
+    /* bind variables to their values given in the fclosure */
+    vlength = VecTotSize(clos->vl.vectorl[VSizeOff]);
+    /* vector length must be positive (it has to have a function at least) */
+    if (vlength < 1)
+       errorh1(Vermisc,"funcall: fclosure has wrong size ",nil,FALSE,0, clos);
+
+    numvars = (vlength - 1);   /* number of varibles */
+    
+    for (i = 1 ; i < vlength ; i += 1)
+    {
+       atm_dtpr = clos->v.vector[i];   /* car is symbol name */
+       value_dtpr = atm_dtpr->d.cdr;   /* car: value, cdr:  fixnum count */
+
+       if(value_dtpr->d.cdr->i == 0)
+               tcase = Case_A;         /* first call */
+       else {
+           lbnp = locatevar(atm_dtpr,&foundc,bnp-1);
+           if (!foundc)
+           {
+               /* didn't find the expected closure, count must be
+                  wrong, correct it and assume case (a)
+                */
+               tcase = Case_A;
+               value_dtpr->d.cdr->i = 0;
+           }
+           else if(lbnp) tcase = Case_C ; /* found intermediate lambda bnd*/
+           else tcase = Case_B;           /* no intermediate lambda bind */
+       }
+
+       /* now bind the value if necessary */
+       switch(tcase) {
+           case Case_A: PUSHDOWN(atm_dtpr->d.car,value_dtpr->d.car);
+                        PUSHVAL(clos_marker,atm_dtpr);
+                        value_dtpr->d.cdr->i += 1;
+                        break;
+                        
+           case Case_B: break;         /* nothing to do */
+
+           case Case_C: /* push first bound value after last close */
+                        PUSHDOWN(atm_dtpr->d.car,lbnp->val);
+                        PUSHVAL(clos_marker,atm_dtpr);
+                        value_dtpr->d.cdr->i += 1;
+                        break;
+       }
+    }
+
+    if(funcallp)
+       handy = Ifuncal(clos->v.vector[0]);
+    else {
+       handy = lbot[-2].val;   /* get args to apply.  This is hacky and may
+                                          fail if apply is changed */
+       lbot = np;
+       protect(clos->v.vector[0]);
+       protect(handy);
+       handy = Lapply();
+    }
+
+    xpopnames(oldbnp); /* pop names with consideration for closure markers */
+    
+    if(!funcallp) Restorestack();
+    return(handy);
+}
+
+/* xpopnames :: pop values from bindstack, but look out for
+ *  closure markers.  This is  used (instead of the faster popnames)
+ * when we know there will be closure markers or when we can't
+ * be sure that there won't be closure markers (eg. in non-local go's)
+ */
+xpopnames(llimit)
+register struct nament *llimit;
+{
+    register struct nament *rnp, *lbnp;
+    lispval atm_dtpr, value_dtpr;
+    int foundc;
+
+    for(rnp = bnp; --rnp >= llimit;)
+    {
+        if(rnp->atm == clos_marker)
+       {
+           atm_dtpr = rnp->val;
+           value_dtpr = atm_dtpr->d.cdr;
+           if(value_dtpr->d.cdr->i <= 1)
+           {
+               /* this is the only occurance of this closure variable
+                * just restore current value to this closure.
+                */
+               value_dtpr->d.car = atm_dtpr->d.car->a.clb;
+           }
+           else {
+               /* locate the last lambda before the next occurance of
+                * this closure and store the current symbol's value
+                * there
+                */
+               lbnp = locatevar(atm_dtpr,&foundc,rnp-2);
+               if(!foundc)
+               {
+                   /* strange, there wasn't a closure to be found.
+                    * well, we will fix things up so the count is
+                    * right.
+                    */
+                   value_dtpr->d.car = atm_dtpr->d.car->a.clb;
+                   value_dtpr->d.cdr->i = 1;
+               }
+               else if (lbnp) {
+                   /* note how the closures value isn't necessarily
+                    * stored in the closure, it may be stored on
+                    * the bindstack
+                    */
+                   lbnp->val = atm_dtpr->d.car->a.clb;
+               }
+               /* the case where lbnp is 0 should never happen, but
+                  if it does, we can just do nothing safely
+                */
+           }
+           value_dtpr->d.cdr->i -= 1;
+       } else rnp->atm->a.clb = rnp->val;  /* the normal case */
+    }
+    bnp = llimit;
+}
+
+
+struct nament *
+locatevar(clos,foundc,rnp)
+struct nament *rnp;
+lispval clos;
+int *foundc;
+{
+    register struct nament  *retbnp;
+    lispval symb;
+
+    retbnp = (struct nament *) 0;
+    *foundc = 0;
+    
+    symb = clos->d.car;
+    
+    for(  ; rnp >= orgbnp ; rnp--)
+    {
+       if((rnp->atm == clos_marker) && (rnp->val == clos))
+       {
+           *foundc = 1;        /* found the closure */
+           return(retbnp);
+       }
+       if(rnp->atm == symb) retbnp = rnp;
+    }
+    return(retbnp);    
+}
+
+lispval
+LIfss()
+{
+       register lispval atm_dtpr, value_dtpr;
+       struct nament *oldbnp = bnp, *lbnp;
+       int tcase, foundc = 0;
+       lispval newval;
+       int argc = 1;
+       Savestack(2);
+
+       switch(np-lbot) {
+       case 2:
+               newval = np[-1].val;
+               argc++;
+       case 1:
+               atm_dtpr = lbot->val;
+               value_dtpr = atm_dtpr->d.cdr;
+               break;
+       default:
+               argerr("int:fclosure-symbol-stuff");
+       }
+       /* this code is copied from Ifclosure */
+
+       if(value_dtpr->d.cdr->i==0)
+               tcase = Case_A; /* closure is not active */
+       else {
+               lbnp = locatevar(atm_dtpr,&foundc,bnp-1);
+               if (!foundc)
+               {
+                       /* didn't find closure, count must be wrong,
+                          correct it and assume case (a).*/
+                       tcase = Case_A;
+                       value_dtpr->d.cdr->i = 0;
+               }
+               else if(lbnp) tcase = Case_C; /* found intermediate lambda*/
+               else tcase = Case_B;
+       }
+
+       switch(tcase) {
+       case Case_B:
+               if(argc==2) return(atm_dtpr->d.car->a.clb = newval);
+               return(atm_dtpr->d.car->a.clb);
+
+       case Case_A:
+               if(argc==2) return(value_dtpr->d.car = newval);
+               return(value_dtpr->d.car);
+
+       case Case_C:
+               if(argc==2) return(lbnp->val = newval);
+               return(lbnp->val);
+       }
+       /*NOTREACHED*/
+}
diff --git a/usr/src/ucb/lisp/franz/fasl.c b/usr/src/ucb/lisp/franz/fasl.c
new file mode 100644 (file)
index 0000000..e3b81df
--- /dev/null
@@ -0,0 +1,747 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: fasl.c,v 1.8 83/09/12 14:17:38 sklower Exp $";
+#endif
+
+/*                                     -[Thu Jun  2 21:44:26 1983 by jkf]-
+ *     fasl.c                          $Locker:  $
+ * compiled lisp loader
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include <sys/types.h>
+#include "lispo.h"
+#include "chkrtab.h"
+#include "structs.h"
+#include "frame.h"
+
+/* fasl  -  fast loader                                j.k.foderaro
+ * this loader is tuned for the lisp fast loading application
+ * any changes in the system loading procedure will require changes
+ * to this file
+ *
+ *  The format of the object file we read as input:
+ *  text segment:
+ *    1) program text - this comes first.
+ *    2) binder table - one word entries, see struct bindage
+ *                     begins with symbol:  bind_org
+ *    3) litterals - exploded lisp objects. 
+ *                     begins with symbol:  lit_org
+ *                     ends with symbol:    lit_end
+ * data segment:
+ *     not used
+ *
+ *
+ *  these segments are created permanently in memory:
+ *     code segment - contains machine codes to evaluate lisp functions.
+ *     linker segment - a list of pointers to lispvals.  This allows the
+ *                     compiled code to reference constant lisp objects.
+ *                     The first word of the linker segment is a gc link
+ *                     pointer and does not point to a literal.  The
+ *                     symbol binder is assumed to point to the second
+ *                     longword in this segment.  The last word in the
+ *                     table is -1 as a sentinal to the gc marker.
+ *                     The number of real entries in the linker segment 
+ *                     is given as the value of the linker_size symbol.  
+ *                     Taking into account the 2 words required for the
+ *                     gc, there are 4*linker_size + 8 bytes in this segment.
+ *     transfer segment - this is a transfer table block.  It is used to
+ *                     allow compiled code to call other functions 
+ *                     quickly.  The number of entries in the transfer table is
+ *                     given as the value of the trans_size symbol.
+ *
+ *  the following segments are set up in memory temporarily then flushed
+ *     binder segment -  a list of struct bindage entries.  They describe
+ *                     what to do with the literals read from the literal
+ *                     table.  The binder segment begins in the file
+ *                     following the bindorg symbol.
+ *     literal segment - a list of characters which _Lread will read to 
+ *                     create the lisp objects.  The order of the literals
+ *                     is:
+ *                      linker literals - used to fill the linker segment.
+ *                      transfer table literals - used to fill the 
+ *                        transfer segment
+ *                      binder literals - these include names of functions
+ *                        to bind interspersed with forms to evaluate.
+ *                        The meanings of the binder literals is given by
+ *                        the values in the binder segment.
+ *     string segment - this is the string table from the file.  We have
+ *                      to allocate space for it in core to speed up
+ *                      symbol referencing.
+ *
+ */
+
+\f
+/* external functions called or referenced */
+
+lispval qcons(),qlinker(),qget();
+int _qf0(), _qf1(), _qf2(), _qf3(), _qf4(), _qfuncl(), svkludg(),qnewint();
+int qnewdoub(),qoneplus(),qoneminus(), wnaerr();
+lispval Lread(), Lcons(), Lminus(), Ladd1(), Lsub1(), Lplist(), Lputprop();
+lispval Lprint(), Lpatom(), Lconcat(), Lget(), Lmapc(), Lmapcan();
+lispval Llist(), Ladd(), Lgreaterp(), Lequal(), Ltimes(), Lsub(), Ipurcopy();
+lispval Lncons(), Ibindvars(), Iunbindvars(),error();
+int Inonlocalgo();
+lispval Istsrch();
+int mcount(), qpushframe();
+extern int mcounts[],mcountp,doprof;
+
+extern lispval *tynames[];
+extern struct frame *errp;
+extern char _erthrow[];
+
+extern int initflag;           /* when TRUE, inhibits gc */
+
+char *alloca();                        /* stack space allocator */
+
+/* mini symbol table, contains the only external symbols compiled code
+   is allowed to reference
+ */
+
+
+struct ssym { char *fnam;      /* pointer to string containing name */
+             int  floc;        /* address of symbol */
+             int  ord;         /* ordinal number within cur sym tab */
+
+             } Symbtb[] 
+                         = {
+                            "trantb",  0,      -1,   /* must be first */
+                            "linker",  0,      -1,   /* must be second */
+                            "mcount",    (int) mcount,   -1,
+                            "mcounts",   (int) mcounts,  -1,
+                            "_wnaerr",   (int) wnaerr, -1,
+                            "_qnewint",   (int) qnewint,  -1,
+                            "_qnewdoub",   (int) qnewdoub,  -1,
+                            "_qcons",    (int) qcons,    -1,
+                            "_qoneplus", (int) qoneplus, -1,
+                            "_qoneminus", (int) qoneminus, -1,
+                            "_typetable",  (int) typetable,  -1,
+                            "_tynames",  (int) tynames,  -1,
+                            "_qget",     (int) qget,     -1,
+                            "_errp",     (int) &errp,          -1,
+                            "_Inonlocalgo",  (int) Inonlocalgo, -1,
+                            "__erthrow",  (int) _erthrow,      -1,
+                            "_error",    (int) error,          -1,
+                            "_qpushframe",  (int) qpushframe,  -1,
+                            "_retval",         (int)&retval,   -1,
+                            "_lispretval",     (int)&lispretval,-1,
+#ifndef NPINREG
+                            "_np",       (int) &np,      -1,
+                            "_lbot",     (int) &lbot,    -1,
+#endif
+#ifndef NILIS0
+                            "_nilatom",  (int) &nilatom, -1,
+#endif
+                            "_bnp",      (int) &bnp,     -1,
+                            "_Ibindvars", (int) Ibindvars, -1,
+                            "_Iunbindvars", (int) Iunbindvars, -1
+                            };
+
+#define SYMMAX ((sizeof Symbtb) / (sizeof (struct ssym)))
+
+struct nlist syml;             /* to read a.out symb tab */
+extern int *bind_lists;                /* gc binding lists       */
+
+/* bindage structure:
+ *  the bindage structure describes the linkages of functions and name,
+ *  and tells which functions should be evaluated.  It is mainly used 
+ *  for the non-fasl'ing of files, we only use one of the fields in fasl
+ */
+struct bindage
+{
+     int     b_type;                   /* type code, as described below */
+};
+
+/* the possible values of b_type
+ * -1 - this is the end of the bindage entries
+ * 0  - this is a lambda function
+ * 1  - this is a nlambda function
+ * 2  - this is a macro function
+ * 99 - evaluate the string
+ *
+ */
+
+
+extern struct trtab *trhead;   /* head of list of transfer tables          */
+extern struct trent *trcur;    /* next entry to allocate                   */
+extern int trleft;             /* # of entries left in this transfer table */
+
+struct trent *gettran();       /* function to allocate entries */
+
+/* maximum number of functions */
+#define MAXFNS 2000
+\f
+lispval Lfasl()
+{
+       extern int holend,usehole;
+       extern int uctolc;
+       extern char *curhbeg;
+       struct argent *svnp;
+       struct exec exblk;      /* stores a.out header */
+       FILE *filp, *p, *map;   /* file pointer */
+       int domap,note_redef;
+       lispval handy,debugmode;
+       struct relocation_info reloc;
+       struct trent *tranloc;
+       int trsize;
+       int i,j,times, *iptr;
+       int  funloc[MAXFNS];    /* addresses of functions rel to txt org */
+       int funcnt = 0;
+
+       /* symbols whose values are taken from symbol table of .o file */
+       int bind_org = 0;               /* beginning of bind table */
+       int lit_org = 0;        /* beginning of literal table */
+       int lit_end;            /* end of literal table  */
+       int trans_size = 0;     /* size in entries of transfer table */
+       int linker_size;        /* size in bytes   of linker table 
+                                       (not counting gc ptr) */
+
+       /* symbols which hold the locations of the segments in core and 
+       * in the file
+       */
+       char *code_core_org,    /* beginning of code segment */
+            *lc_org,  /* beginning of linker segment */
+            *lc_end,  /* last word in linker segment */
+            *literal_core_org, /* beginning of literal table   */
+            *binder_core_org,  /* beginning of binder table   */
+            *string_core_org;
+
+       int /*string_file_org,  /* location of string table in file */
+           string_size,        /* number of chars in string table */
+           segsiz;             /* size of permanent incore segment */
+
+       char *symbol_name;
+       struct bindage *curbind;
+       lispval rdform, *linktab;
+       int ouctolc;
+       int debug = 0;
+       lispval currtab,curibase;
+       char ch,*filnm,*nfilnm;
+       char tempfilbf[100];
+       char *strcat();
+       long lseek();
+       Keepxs();
+       
+
+       switch(np-lbot) {
+       case 0:
+               protect(nil);
+       case 1:
+               protect(nil);
+       case 2:
+               protect(nil);
+       case 3:
+               break;
+       default:
+               argerr("fasl");
+       }
+       filnm = (char *) verify(lbot->val,"fasl: non atom arg");
+
+
+       domap = FALSE;
+       /* debugging */
+       debugmode = Istsrch(matom("debugging"))->d.cdr->d.cdr->d.cdr;
+       if (debugmode != nil) debug = 1;
+        /* end debugging */
+
+
+       /* insure that the given file name ends in .o
+          if it doesnt, copy to a new buffer and add a .o
+          but Allow non .o file names (5mar80 jkf)
+       */
+       tempfilbf[0] = '\0';
+       nfilnm = filnm;         /* same file name for now */
+       if( (i = strlen(filnm)) < 2 ||
+            strcmp(filnm+i-2,".o") != 0)
+       {
+               strcatn(tempfilbf,filnm,96);
+               strcat(tempfilbf,".o");
+               nfilnm = tempfilbf;
+       }
+
+       if ( (filp = fopen(nfilnm,"r")) == NULL)
+          if ((filnm == nfilnm) || ((filp = fopen(filnm,"r")) == NULL))
+              errorh1(Vermisc,"Can't open file",nil,FALSE,9797,lbot->val);
+
+       if ((handy = (lbot+1)->val) != nil )
+       {
+           if((TYPE(handy) != ATOM )   ||
+              (map = fopen(handy->a.pname,
+                           (Istsrch(matom("appendmap"))->d.cdr->d.cdr->d.cdr == nil 
+                                   ? "w" : "a")))  == NULL)
+               error("fasl: can't open map file",FALSE);
+           else 
+           {   domap = TRUE;
+               /* fprintf(map,"Map of file %s\n",lbot->val->a.pname); */
+           }
+       }
+
+       /* set the note redefinition flag */
+       if((lbot+2)->val != nil) note_redef = TRUE;
+       else    note_redef = FALSE;
+
+       /* if nil don't print fasl message */
+       if ( Vldprt->a.clb != nil ) {
+               printf("[fasl %s]",filnm);
+               fflush(stdout);
+       }
+       svnp = np;
+
+
+
+       /* clear the ords in the symbol table */
+       for(i=0 ; i < SYMMAX ; i++) Symbtb[i].ord = -1;
+
+       if( read(fileno(filp),(char *)&exblk,sizeof(struct exec)) 
+               != sizeof(struct exec))
+         error("fasl: header read failed",FALSE);
+         
+       /* check that the magic number is valid */
+
+       if(exblk.a_magic != 0407)
+          errorh1(Vermisc,"fasl: file is not a lisp object file (bad magic number): ",
+               nil,FALSE,0,lbot->val);
+
+       /* read in string table */
+       lseek(fileno(filp),(long)(/*string_file_org =*/N_STROFF(exblk)),0);
+       if( read(fileno(filp), (char *)&string_size , 4) != 4)
+         error("fasl: string table read error, probably old fasl format", FALSE);
+       
+       lbot = np;              /* set up base for later calls */
+        /* allocate space for string table on the stack */
+       string_core_org = alloca(string_size - 4);
+
+       if( read(fileno(filp), string_core_org , string_size - 4)
+               != string_size -4) error("fasl: string table read error ",FALSE);
+       /* read in symbol table and set the ordinal values */
+
+       fseek(filp,(long) (N_SYMOFF(exblk)),0);
+
+       times = exblk.a_syms/sizeof(struct nlist);
+       if(debug) printf(" %d symbols in symbol table\n",times);
+
+       for(i=0; i < times ; i++)
+       {
+          if( fread((char *)&syml,sizeof(struct nlist),1,filp) != 1)
+              error("fasl: Symb tab read error",FALSE);
+       
+          symbol_name = syml.n_un.n_strx - 4 + string_core_org;
+          if(debug) printf("symbol %s\n read\n",symbol_name);
+          if (syml.n_type == N_EXT) 
+          { 
+             for(j=0; j< SYMMAX; j++)
+             {
+                if((Symbtb[j].ord < 0) 
+                         && strcmp(Symbtb[j].fnam,symbol_name)==0)
+                {    Symbtb[j].ord = i;
+                     if(debug)printf("symbol %s ord is %d\n",symbol_name,i);
+                     break;
+                };
+
+             };
+
+             if( j>=SYMMAX )  printf("Unknown symbol %s\n",symbol_name);
+          }
+          else if (((ch = symbol_name[0]) == 's')
+                    || (ch == 'L')
+                    || (ch == '.') )  ;                /* skip this */
+          else if (symbol_name[0] == 'F')
+          {
+              if(funcnt >= MAXFNS)
+                       error("fasl: too many function in file",FALSE);
+              funloc[funcnt++] = syml.n_value;         /* seeing function */
+          }
+          else if (!bind_org && (strcmp(symbol_name, "bind_org") == 0))
+            bind_org = syml.n_value;
+          else if (strcmp(symbol_name, "lit_org") == 0)
+            lit_org = syml.n_value;
+          else if (strcmp(symbol_name, "lit_end") == 0)
+            lit_end = syml.n_value;
+          else if (strcmp(symbol_name, "trans_size") == 0)
+            trans_size = syml.n_value;
+          else if (strcmp(symbol_name, "linker_size") == 0)
+            linker_size = syml.n_value;
+       }
+
+#if m_68k
+       /* 68k only, on the vax the symbols appear in the correct order */
+       { int compar();
+         qsort(funloc,funcnt,sizeof(int),compar);
+       }
+#endif
+
+       if (debug)
+         printf("lit_org %x,  lit_end %x, bind_org %x, linker_size %x\n",
+               lit_org, lit_end, bind_org, linker_size);
+       /* check to make sure we are working with the right format */
+       if((lit_org == 0) || (lit_end == 0))
+          errorh1(Vermisc,"File not in new fasl format",nil,FALSE,0,lbot->val);
+
+        /*----------------*/
+
+       /* read in text segment  up to beginning of binder table */
+
+       segsiz = bind_org + 4*linker_size + 8 + 3; /* size is core segment size
+                                                * plus linker table size
+                                                * plus 2 for gc list
+                                                * plus 3 to round up to word
+                                                */
+
+       lseek(fileno(filp),(long)sizeof(struct exec),0);
+       code_core_org = (char *) csegment(OTHER,segsiz,TRUE);
+       if(read(fileno(filp),code_core_org,bind_org) != bind_org)
+           error("Read error in text ",FALSE);
+
+  if(debug) {
+       printf("Read %d bytes of text into 0x%x\n",bind_org,code_core_org);
+        printf(" incore segment size: %d (0x%x)\n",segsiz,segsiz);
+        }
+        
+       /* linker table is 2 entries (8 bytes) larger than the number of
+        * entries given by linker_size .  There must be a gc word at
+        * the beginning and a -1 at the end
+        */
+       lc_org = code_core_org + bind_org;
+       lc_end = lc_org + 4*linker_size + 4; 
+                                       /* address of gc sentinal last */
+
+       if(debug)printf("lin_cor_org: %x, link_cor_end %x\n",
+                                     lc_org,
+                                     lc_end);
+       Symbtb[1].floc = (int) (lc_org + 4);
+
+       /* set the linker table to all -1's so we can put in the gc table */
+       for( iptr = (int *)(lc_org + 4 ); 
+            iptr <= (int *)(lc_end); 
+            iptr++)
+         *iptr = -1;
+
+
+       /* link our table into the gc tables */
+       /* only do so if we will not purcopy these tables */
+       if(Vpurcopylits->a.clb == nil)
+       {
+           *(int *)lc_org = (int)bind_lists;   /* point to current */
+           bind_lists = (int *) (lc_org + 4); /* point to first
+                                                               item */
+       }
+
+       /* read the binder table and literals onto the stack */
+
+       binder_core_org =  alloca(lit_end - bind_org);
+       read(fileno(filp),binder_core_org,lit_end-bind_org);
+
+       literal_core_org = binder_core_org + lit_org - bind_org;
+
+       /* check if there is a transfer table required for this
+        * file, and if so allocate one of the necessary size
+        */
+
+       if(trans_size > 0)
+       {
+           tranloc = gettran(trans_size);
+           Symbtb[0].floc = (int) tranloc;
+       }
+
+       /* now relocate the necessary symbols in the text segment */
+
+       fseek(filp,(long)(sizeof(struct exec) + exblk.a_text + exblk.a_data),0);
+       times = (exblk.a_trsize)/sizeof(struct relocation_info);
+               
+       /* the only symbols we will relocate are references to  
+               external symbols.  They are recognized by 
+               extern and pcrel set.
+        */
+
+        for( i=1; i<=times ; i++)
+           {
+               if( fread((char *)&reloc,sizeof(struct relocation_info),1,filp) != 1)
+                  error("Bad text reloc read",FALSE);
+            if(reloc.r_extern)
+            {
+               for(j=0; j < SYMMAX; j++)
+               {
+
+                  if(Symbtb[j].ord == reloc.r_symbolnum)  /* look for this sym */
+                   {
+#define offset(p) (((p).r_pcrel) ? ((int) code_core_org): 0)
+                     if(debug && FALSE) printf("Relocating %d (ord %d) at %x\n",
+                                        j, Symbtb[j].ord, reloc.r_address);
+                       if (Symbtb[j].floc == (int)  mcounts) {
+                           *(int *)(code_core_org+reloc.r_address) 
+                              += mcountp - offset(reloc); 
+                           if(doprof){
+                            if (mcountp == (int) &mcounts[NMCOUNT-2])
+                               printf("Ran out of counters; increas NMCOUNT in fasl.c\n");
+                            if (mcountp < (int) &mcounts[NMCOUNT-1])
+                               mcountp += 4;
+                           }
+                       } else
+                           *(int *)(code_core_org+reloc.r_address) 
+                              += Symbtb[j].floc - offset(reloc); 
+                         
+                       break;
+                     
+                     }
+                };
+                if( j >= SYMMAX) if(debug) printf("Couldnt find ord # %d\n",
+                                                  reloc.r_symbolnum);
+            }
+
+           }
+       
+       if ( Vldprt->a.clb != nil ) {
+               putchar('\n');
+               fflush(stdout);
+       }
+
+       /* set up a fake port so we can read from core */
+       /* first find a free port                      */
+
+       p = stdin;
+       for( ; p->_flag & (_IOREAD|_IOWRT|_IORW) ; p++)
+          if( p >= _iob + _NFILE)
+              error(" No free file descriptor for fasl ",FALSE);
+              
+       p->_flag = _IOREAD | _IOSTRG;
+       p->_base = p->_ptr = (char *) literal_core_org;   /* start at beginning of lit */
+       p->_cnt = lit_end - lit_org;
+
+       if(debug)printf("lit_org %d, charstrt  %d\n",lit_org, p->_base);
+       /* the first forms we wish to read are those literals in the 
+        * literal table, that is those forms referenced by an offset
+        * from r8 in  compiled code
+        */
+
+       /* to read in the forms correctly, we must set up the read table
+        */
+       currtab = Vreadtable->a.clb;
+       Vreadtable->a.clb = strtab;             /* standard read table */
+       curibase = ibase->a.clb;
+       ibase->a.clb = inewint(10);             /* read in decimal */
+       ouctolc = uctolc;       /* remember value of uctolc flag */
+
+       PUSHDOWN(gcdis,tatom);                  /* turn off gc */
+
+       i = 1;  
+       linktab = (lispval *)(lc_org +4);
+       while (linktab < (lispval *)lc_end)
+       {
+          np = svnp;
+          protect(P(p));
+          uctolc = FALSE;
+          handy = (lispval)Lread();
+          if (Vpurcopylits->a.clb != nil) {
+               handy = Ipurcopy(handy);
+          }
+          uctolc = ouctolc;
+          getc(p);                     /* eat trailing blank */
+          if(debugmode != nil)
+          {   printf("form %d read: ",i++);
+              printr(handy,stdout); 
+              putchar('\n');
+              fflush(stdout);
+          }
+          *linktab++ = handy;
+       }
+
+       /* process the transfer table if one is used            */
+       trsize = trans_size;
+       while(trsize--)
+       {
+           np = svnp;
+           protect(P(p));
+           uctolc = FALSE;
+           handy = Lread();        /* get function name */
+           uctolc = ouctolc;
+           getc(p);
+           tranloc->name = handy;
+           tranloc->fcn = qlinker;     /* initially go to qlinker */
+           tranloc++;
+       }
+
+
+
+       /* now process the binder table, which contains pointers to 
+          functions to link in and forms to evaluate.
+       */
+       funcnt = 0;
+
+       curbind = (struct bindage *) binder_core_org;
+       for( ; curbind->b_type != -1 ; curbind++) 
+       {
+           np = svnp;
+           protect(P(p));
+           uctolc = FALSE;             /* inhibit uctolc conversion */
+           rdform = Lread();
+           /* debugging */
+           if(debugmode != nil) { printf("link form read: ");
+                       printr(rdform,stdout);
+                       printf("  ,type: %d\n",
+                                curbind->b_type);
+                       fflush(stdout);
+                     }
+           /* end debugging */
+           uctolc = ouctolc;           /* restore previous state */
+           getc(p);                    /* eat trailing null */
+           protect(rdform);
+           if(curbind->b_type <= 2)    /* if function type */
+           { 
+              handy = newfunct();
+              if (note_redef && (rdform->a.fnbnd != nil))
+              {
+                  printr(rdform,stdout);
+                  printf(" redefined\n");
+              }
+              rdform->a.fnbnd = handy;
+              handy->bcd.start = (lispval (*)())(code_core_org + funloc[funcnt++]);
+              handy->bcd.discipline =
+                 (curbind->b_type == 0 ? lambda :
+                      curbind->b_type == 1 ? nlambda :
+                         macro);
+              if(domap) {
+                  fprintf(map,"%s\n%x\n",rdform->a.pname,handy->bcd.start);
+              }
+           }
+           else {
+               Vreadtable->a.clb = currtab;
+               ibase->a.clb = curibase;
+
+               /* debugging */
+               if(debugmode != nil) {
+                       printf("Eval: ");
+                       printr(rdform,stdout);
+                       printf("\n");
+                       fflush(stdout);
+               };
+               /* end debugging */
+
+               eval(rdform);           /* otherwise eval it */
+
+               if(uctolc) ouctolc = TRUE; /* if changed by eval, remember */
+               curibase = ibase->a.clb;
+               ibase->a.clb = inewint(10);
+               Vreadtable->a.clb = strtab;
+          }
+       };
+             
+       p->_cnt = p->_file = p->_flag = 0;      /* give up file descriptor */
+       p->_ptr = p-> _base = (char *) 0;
+
+       POP;                    /* restore state of gcdisable variable */
+
+       Vreadtable->a.clb = currtab;
+       chkrtab(currtab);
+       ibase->a.clb = curibase;
+
+       fclose(filp);
+       if(domap) fclose(map);
+       Freexs();
+       return(tatom);
+}
+
+#if m_68k
+/* function used in qsort for 68k version only */
+compar(arg1,arg2)
+int *arg1,*arg2;
+{
+       if(*arg1 < *arg2) return (-1);
+        else if (*arg1 == *arg2) return (0);
+       else return(1);
+}
+#endif
+
+/* gettran :: allocate a segment of transfer table of the given size   */
+
+struct trent *
+gettran(size)
+{
+       struct trtab *trp;
+       struct trent *retv;
+       int ousehole;
+       extern int usehole;
+
+       if(size > TRENTS)
+         error("transfer table too large",FALSE);
+       
+       if(size > trleft)
+       {
+           /* allocate a new transfer table */
+           /* must not allocate in the hole or we cant modify it */
+           ousehole = usehole; /* remember old value */
+           usehole = FALSE;
+           trp = (struct trtab *)csegment(OTHER,sizeof(struct trtab),FALSE);
+           usehole = ousehole;
+
+           trp->sentinal = 0;          /* make sure the sentinal is 0 */
+           trp->nxtt = trhead; /* link at beginning of table  */
+           trhead = trp;
+           trcur = &(trp->trentrs[0]); /* begin allocating here        */
+           trleft = TRENTS;
+       }
+
+       trleft = trleft - size;
+       retv = trcur;
+       trcur = trcur + size;
+       return(retv);
+}
+
+/* clrtt :: clear transfer tables, or link them all up;
+ * this has two totally opposite functions:
+ * 1) all transfer tables are reset so that all function calls will go
+ * through qlinker
+ * 2) as many transfer tables are set up to point to bcd functions
+ *    as possible
+ */
+clrtt(flag)
+{
+       /*  flag = 0 :: set to qlinker
+        *  flag = 1 :: set to function bcd binding if possible
+        */
+       register struct trtab *temptt;
+       register struct trent *tement;
+       register lispval fnb;
+
+       for (temptt = trhead; temptt != 0 ; temptt = temptt->nxtt)
+       { 
+           for(tement = &temptt->trentrs[0] ; tement->fcn != 0 ; tement++)
+           {   if(flag == 0 || TYPE(fnb=tement->name->a.fnbnd) != BCD
+                            || TYPE(fnb->bcd.discipline) == STRNG)
+               tement->fcn =  qlinker;
+               else tement->fcn = fnb->bcd.start;
+           }
+       }
+}
+
+/* chktt - builds a list of transfer table entries which don't yet have
+  a function associated with them, i.e if this transfer table entry
+  were used, an undefined function error would result
+ */
+lispval 
+chktt()
+{
+       register struct trtab *temptt;
+       register struct trent *tement;
+       register lispval retlst,curv;
+       Savestack(4);
+
+       retlst = newdot();              /* build list of undef functions */
+       protect(retlst);
+       for (temptt = trhead; temptt != 0 ; temptt = temptt->nxtt)
+       { 
+            for(tement = &temptt->trentrs[0] ; tement->fcn != 0 ; tement++)
+           {
+              if(tement->name->a.fnbnd == nil)
+              {
+                 curv= newdot();
+                 curv->d.car = tement->name;
+                 curv->d.cdr = retlst->d.cdr;
+                 retlst->d.cdr = curv;
+               }
+            }
+        }
+        Restorestack();
+        return(retlst->d.cdr);
+}
diff --git a/usr/src/ucb/lisp/franz/fex1.c b/usr/src/ucb/lisp/franz/fex1.c
new file mode 100644 (file)
index 0000000..1523113
--- /dev/null
@@ -0,0 +1,400 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: fex1.c,v 1.3 83/09/07 17:55:28 sklower Exp $";
+#endif
+
+/*                                     -[Sat Mar  5 19:50:28 1983 by layer]-
+ *     fex1.c                          $Locker:  $
+ * nlambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+#include "frame.h"
+
+/* Nprog ****************************************************************/
+/* This first sets the local variables to nil while saving their old   */
+/* values on the name stack.  Then, pointers to various things are     */
+/* saved as this function may be returned to by an "Ngo" or by a       */
+/* "Lreturn".  At the end is the loop that cycles through the contents */
+/* of the prog.                                                                */
+
+lispval
+Nprog() {
+       register lispval where, temp;
+       struct nament *savedbnp = bnp;
+       extern struct frame *errp;
+       pbuf pb;
+       extern int retval;
+       extern lispval lispretval;
+
+       if((np-lbot) < 1) chkarg(1,"prog");
+
+       /* shallow bind the local variables to nil */
+       if(lbot->val->d.car != nil)
+       {
+           for( where = lbot->val->d.car ; where != nil; where = where->d.cdr )
+           {
+               if(TYPE(where) != DTPR || TYPE(temp=where->d.car) != ATOM)
+                   errorh1(Vermisc,
+                          "Illegal local variable list in prog ",nil,FALSE,
+                          1,where);
+               PUSHDOWN(temp,nil);
+           }
+       }
+
+       /* put a frame on the stack which can be 'return'ed to or 'go'ed to */
+       errp = Pushframe(F_PROG,nil,nil);
+
+       where = lbot->val->d.cdr;       /* first thing in the prog body */
+
+       switch (retval) {
+       case C_RET:     /*
+                        * returning from this prog, value to return
+                        * is in lispretval
+                        */
+                       errp = Popframe();
+                       popnames(savedbnp);
+                       return(lispretval);
+
+       case C_GO:      /*
+                        * going to a certain label, label to go to in
+                        * in lispretval
+                        */
+                       where = (lbot->val)->d.cdr;
+                       while ((TYPE(where) == DTPR) 
+                              && (where->d.car != lispretval))
+                               where = where->d.cdr;
+                       if (where->d.car == lispretval) {
+                               popnames(errp->svbnp);
+                               break;
+                       }
+                       /* label not found in this prog, must 
+                        * go up to higher prog
+                        */
+                       errp = Popframe();      /* go to next frame */
+                       Inonlocalgo(C_GO,lispretval,nil);
+
+                       /* NOT REACHED */
+
+       case C_INITIAL: break;
+
+       }
+
+       while (TYPE(where) == DTPR)
+               {
+               temp = where->d.car;
+               if((TYPE(temp))!=ATOM) eval(temp);
+               where = where->d.cdr;
+               }
+       if((where != nil) && (TYPE(where) != DTPR)) 
+           errorh1(Vermisc,"Illegal form in prog body ", nil,FALSE,0,where);
+       errp = Popframe();
+       popnames(savedbnp);     /* pop off locals */
+       return(nil);
+}
+
+lispval globtag;
+/*
+   Ncatch is now linked to the lisp symbol *catch , which has the form
+     (*catch tag form)
+    tag is evaluated and then the catch entry is set up.
+      then form is evaluated
+    finally the catch entry is removed.
+
+  *catch is still an nlambda since its arguments should not be evaluated
+   before this routine is called.
+
+   (catch form [tag]) is translated to (*catch 'tag form) by a macro.
+ */
+lispval
+Ncatch()
+{
+       register lispval tag;
+       pbuf pb;
+       Savestack(3);           /* save stack pointers */
+
+       if((TYPE(lbot->val))!=DTPR) return(nil);
+       protect(tag = eval(lbot->val->d.car));  /* protect tag from gc */
+
+       errp = Pushframe(F_CATCH,tag,nil);
+
+       switch(retval) {
+
+       case C_THROW:   /*
+                        * value thrown is in lispretval
+                        */
+                       break;
+
+       case C_INITIAL: /*
+                        * calculate value of expression
+                        */
+                        lispretval = eval(lbot->val->d.cdr->d.car);
+       }
+                       
+                       
+       errp = Popframe();
+       Restorestack();
+       return(lispretval);
+}
+/* (errset form [flag])  
+   if present, flag determines if the error message will be printed
+   if an error reaches the errset.
+   if no error occurs, errset returns a list of one element, the 
+    value returned from form.
+   if an error occurs, nil is usually returned although it could
+    be non nil if err threw a non nil value 
+ */
+
+lispval Nerrset()
+{
+       lispval temp,flag;
+       pbuf pb;
+       Savestack(0);
+
+       if(TYPE(lbot->val) != DTPR) return(nil);        /* no form */
+
+       /* evaluate and save flag first */
+       flag = lbot->val->d.cdr;
+       if(TYPE(flag) == DTPR) flag = eval(flag->d.car); 
+       else flag = tatom;      /* if not present , assume t */
+       protect(flag);
+
+       errp = Pushframe(F_CATCH,Verall,flag);
+
+       switch(retval) {
+
+       case C_THROW:   /*
+                        * error thrown to this routine, value thrown is
+                        * in lispretval
+                        */
+                       break;
+
+       case C_INITIAL: /*
+                        * normally just evaluate expression and listify it.
+                        */
+                       temp = eval(lbot->val->d.car);
+                       protect(temp);
+                       (lispretval = newdot())->d.car = temp;
+                       break;
+       }
+
+       errp = Popframe();
+       Restorestack();
+       return(lispretval);
+}
+       
+/* this was changed from throw to *throw 21nov79
+   it is now a lambda and really should be called Lthrow
+*/
+lispval
+Nthrow()
+{
+       switch(np-lbot) {
+       case 0:
+               protect(nil);
+       case 1:
+               protect(nil);
+       case 2: break;
+       default:
+               argerr("throw");
+       }
+       Inonlocalgo(C_THROW,lbot->val,(lbot+1)->val);
+       /* NOT REACHED */
+}
+
+
+
+/* Ngo ******************************************************************/
+/* First argument only is checked - and must be an atom or evaluate    */
+/* to one.                                                             */
+lispval
+Ngo() 
+{
+    register lispval temp;
+    chkarg(1,"go");
+
+    temp = (lbot->val)->d.car;
+    if (TYPE(temp) != ATOM)
+    {
+       temp = eval(temp);
+       while(TYPE(temp) != ATOM) 
+         temp = errorh1(Vermisc,"Illegal tag to go to",nil,TRUE, 0,lbot->val);
+    }
+    Inonlocalgo(C_GO,temp,nil);
+    /* NOT REACHED */
+}
+
+
+/* Nreset ***************************************************************/
+/* All arguments are ignored.  This just returns-from-break to depth 0.        */
+lispval
+Nreset()
+{
+    Inonlocalgo(C_RESET,inewint(0),nil);
+}
+
+/* Nresetio *************************************************************/
+
+lispval
+Nresetio() {
+       register FILE *p;
+
+       for(p = &_iob[3]; p < _iob + _NFILE; p++) {
+               if(p->_flag & (_IOWRT | _IOREAD)) fclose(p);
+               }
+       return(nil);
+
+}
+
+
+/* Nbreak ***************************************************************/
+/* If first argument is not nil, this is evaluated and printed.  Then  */
+/* error is called with the "breaking" message.                                */
+
+lispval
+Nbreak()
+{
+       register lispval hold; register FILE *port;
+       port = okport(Vpoport->a.clb,stdout);
+       fprintf(port,"Breaking:");
+
+       if ((hold = lbot->val) != nil && ((hold = hold->d.car) != nil))
+       {
+               printr(hold,port);
+       }
+       putc('\n',port);
+       dmpport(port);
+       return(errorh(Verbrk,"",nil,TRUE,0));
+}
+
+
+/* Nexit ****************************************************************/
+/* Just calls lispend with no message.                                 */
+Nexit()
+       {
+       lispend("");
+       }
+
+
+/* Nsys *****************************************************************/
+/* Just calls lispend with no message.                                 */
+
+lispval
+Nsys()
+       {
+       lispend("");
+       }
+
+
+
+
+lispval
+Ndef() {
+       register lispval arglist, body, name, form;
+       
+       form = lbot->val;
+       name = form->d.car;
+       body = form->d.cdr->d.car;
+       arglist = body->d.cdr->d.car;
+       if((TYPE(arglist))!=DTPR && arglist != nil)
+               error("Warning: defining function with nonlist of args",
+                       TRUE);
+       name->a.fnbnd = body;
+       return(name);
+}
+
+
+lispval
+Nquote()
+{
+       return((lbot->val)->d.car);
+}
+
+
+lispval
+Nsetq()
+{      register lispval handy, where, value;
+       register int lefttype;
+
+       value = nil;
+       
+       for(where = lbot->val; where != nil; where = handy->d.cdr) {
+               handy = where->d.cdr;
+               if((TYPE(handy))!=DTPR)
+                       error("odd number of args to setq",FALSE);
+               if((lefttype=TYPE(where->d.car))==ATOM) {
+                       if(where->d.car==nil)
+                               error("Attempt to set nil",FALSE);
+                       where->d.car->a.clb = value = eval(handy->d.car);
+                }else if(lefttype==VALUE)
+                       where->d.car->l = value = eval(handy->d.car);
+               else errorh1(Vermisc,
+                           "Can only setq atoms or values",nil,FALSE,0,
+                                       where->d.car);
+       }
+       return(value);
+}
+
+
+lispval
+Ncond()
+{
+       register lispval  where, last;
+
+       where = lbot->val;
+       last = nil;
+       for(;;) {
+               if ((TYPE(where))!=DTPR)
+                       break;
+               if ((TYPE(where->d.car))!=DTPR)
+                       break;
+               if ((last=eval((where->d.car)->d.car)) != nil)
+                       break;
+               where = where->d.cdr;
+       }
+
+       if ((TYPE(where)) != DTPR)
+                       return(nil);
+       where = (where->d.car)->d.cdr;
+       while ((TYPE(where))==DTPR) {
+                       last = eval(where->d.car);
+                       where = where->d.cdr;
+       }
+       return(last);
+}
+
+lispval
+Nand()
+{
+       register lispval current, temp;
+
+       current = lbot->val;
+       temp = tatom;
+       while (current != nil)
+               if ( (temp = current->d.car)!=nil && (temp = eval(temp))!=nil) 
+                       current = current->d.cdr;
+               else {
+                       current = nil;
+                       temp = nil;
+               }
+       return(temp);
+}
+
+
+lispval
+Nor()
+{
+       register lispval current, temp;
+
+       current = lbot->val;
+       temp = nil;
+       while (current != nil)
+               if ( (temp = eval(current->d.car)) == nil)
+                       current = current->d.cdr;
+               else
+                       break;
+       return(temp);
+}
diff --git a/usr/src/ucb/lisp/franz/fex2.c b/usr/src/ucb/lisp/franz/fex2.c
new file mode 100644 (file)
index 0000000..8a1c880
--- /dev/null
@@ -0,0 +1,348 @@
+
+#ifndef lint
+static char *rcsid =
+   "$Header: fex2.c,v 1.3 83/09/07 17:55:38 sklower Exp $";
+#endif
+
+/*                                     -[Mon Jan 31 21:54:52 1983 by layer]-
+ *     fex2.c                          $Locker:  $
+ * nlambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#define NDOVARS 30
+#include "frame.h"
+
+/*
+ * Ndo  maclisp do function.
+ */
+lispval
+Ndo()
+{
+       register lispval current, where, handy;
+       register struct nament *mybnp;
+       lispval temp, atom;
+       lispval body, endtest, endform, varstuff, renewals[NDOVARS] ;
+       struct argent *getem, *startnp;  
+       struct nament *savedbnp = bnp;
+       int count, repeatdo, index;
+       extern struct frame *errp;
+       pbuf pb;
+       Savestack(3);
+
+       current = lbot->val;
+       varstuff = current->d.car;
+
+       switch( TYPE(varstuff) ) {
+
+       case ATOM:                      /* This is old style maclisp do;
+                                          atom is var, cadr(current) = init;
+                                          caddr(current) = repeat etc. */
+               if(varstuff==nil) goto newstyle;
+               current = current->d.cdr;       /* car(current) is now init */
+               PUSHDOWN(varstuff,eval(current->d.car));
+                                       /* Init var.        */
+               *renewals = (current = current->d.cdr)->d.car;
+                                       /* get repeat form  */
+               endtest = (current = current->d.cdr)->d.car;
+               body = current->d.cdr;
+
+               errp = Pushframe(F_PROG,nil,nil);
+
+               switch (retval) {
+                   case C_RET: /*
+                                * returning from this prog, value to return
+                                * is in lispretval
+                                */
+                               errp = Popframe();
+                               popnames(savedbnp);
+                               return(lispretval);
+
+                   case C_GO:  /*
+                                * going to a certain label, label to go to in
+                                * in lispretval
+                                */
+                               where = body;
+                               while ((TYPE(where) == DTPR) 
+                                       & (where->d.car != lispretval))
+                               where = where->d.cdr;
+                               if (where->d.car == lispretval) {
+                                       popnames(errp->svbnp);
+                                       where = where->d.cdr;
+                                       goto singbody;
+                               }
+                               /* label not found in this prog, must 
+                                * go up to higher prog
+                                */
+                               Inonlocalgo(C_GO,lispretval,nil);
+
+                               /* NOT REACHED */
+
+                   case C_INITIAL: break;      /* fall through */
+
+               }
+
+           singtop:
+                   if(eval(endtest)!=nil) {
+                       errp = Popframe();
+                       popnames(savedbnp);
+                       return(nil);
+                   }
+                   where = body;
+                   
+           singbody:
+                   while (TYPE(where) == DTPR)
+                   {
+                       temp = where->d.car;
+                       if((TYPE(temp))!=ATOM) eval(temp);
+                       where = where->d.cdr;
+                   }
+                   varstuff->a.clb = eval(*renewals);
+                   goto singtop;
+       
+
+       newstyle:
+       case DTPR:                      /* New style maclisp do; atom is
+                                          list of things of the form
+                                          (var init repeat)            */
+               count = 0;
+               startnp = np;
+               for(where = varstuff; where != nil; where = where->d.cdr) {
+                                       /* do inits and count do vars. */
+                                       /* requires "simultaneous" eval
+                                          of all inits                 */
+                       while (TYPE(where->d.car) != DTPR)
+                         where->d.car =
+                            errorh1(Vermisc,"do: variable forms must be lists ",
+                            nil,TRUE,0,where->d.car);
+                       handy = where->d.car->d.cdr;
+                       temp = nil;
+                       if(handy !=nil)
+                               temp = eval(handy->d.car);
+                       protect(temp);
+                       count++;
+               }
+               if(count > NDOVARS)
+                       error("More than 15 do vars",FALSE);
+               where = varstuff;
+               getem = startnp;        /* base of stack of init forms */
+               for(index = 0; index < count; index++) {
+
+                       handy = where->d.car;
+                                       /* get var name from group      */
+
+                       atom = handy->d.car;
+                       while((TYPE(atom) != ATOM) || (atom == nil))
+                         atom = errorh1(Vermisc,"do variable must be a non nil symbol ",
+                                                   nil,TRUE,0,atom);
+                       PUSHDOWN(atom,getem->val);
+                       getem++;
+                       handy = handy->d.cdr->d.cdr;
+                       if(handy==nil)
+                               handy = CNIL;  /* be sure not to rebind later */
+                       else
+                               handy = handy->d.car;
+                       renewals[index] = handy;
+
+                                       /* more loop "increments" */
+                       where = where->d.cdr;
+               }
+               np = startnp;           /* pop off all init forms */
+                                       /* Examine End test and End form */
+               current = current->d.cdr;
+               handy = current->d.car;
+               body = current->d.cdr;
+
+               /* 
+                * a do form with a test of nil just does the body once
+                * and returns nil
+                */
+               if (handy == nil) repeatdo = 1; /* just do it once */
+               else repeatdo = -1;             /* do it forever   */
+
+               endtest = handy->d.car;
+               endform = handy->d.cdr;
+
+               where = body;
+
+               errp = Pushframe(F_PROG,nil,nil);
+               while(TRUE) {
+
+                   switch (retval) {
+                   case C_RET: /*
+                                * returning from this prog, value to return
+                                * is in lispretval
+                                */
+                               errp = Popframe();
+                               popnames(savedbnp);
+                               Restorestack();
+                               return(lispretval);
+
+                   case C_GO:  /*
+                                * going to a certain label, label to go to in
+                                * in lispretval
+                                */
+                               where = body;
+                               while ((TYPE(where) == DTPR) 
+                                       & (where->d.car != lispretval))
+                               where = where->d.cdr;
+                               if (where->d.car == lispretval) {
+                                       popnames(errp->svbnp);
+                                       where = where->d.cdr;
+                                       goto bodystart;
+                               }
+                               /* label not found in this prog, must 
+                                * go up to higher prog
+                                */
+                               Inonlocalgo(C_GO,lispretval,nil);
+
+                               /* NOT REACHED */
+
+                   case C_INITIAL: break;      /* fall through */
+
+                   }
+
+           loop:
+                   np = startnp;       /* is bumped when doing repeat forms */
+
+                   if((repeatdo-- == 0) || (eval(endtest) !=nil)) {
+                       for(handy = nil; endform!=nil; endform = endform->d.cdr)
+                       {
+                               handy = eval(endform->d.car);
+                       }
+                       errp = Popframe();
+                       popnames(savedbnp);
+                       Restorestack();
+                       return(handy);
+                   }
+                   
+           bodystart:
+                   while (TYPE(where) == DTPR)
+                   {
+                       temp = where->d.car;
+                       if((TYPE(temp))!=ATOM) eval(temp);
+                       where = where->d.cdr;
+                   }
+                   where = body;
+                   getem = np = startnp;
+                                       /* Simultaneously eval repeat forms */
+                   for(index = 0; index < count; index++) {
+                       temp = renewals[index];
+                       if (temp == nil || temp == CNIL)
+                               protect(temp);
+                       else
+                               protect(eval(temp));
+                   }
+                                       /* now simult. rebind all the atoms */
+                   mybnp = savedbnp;
+                   for(index = 0; index < count; index++) 
+                   {
+                      if( getem->val != CNIL )  /* if this atom has a repeat */
+                       mybnp->atm->a.clb = (getem)->val;  /* rebind */
+                       mybnp++;
+                       getem++;
+                   }
+                   goto loop;
+               }
+           default:
+               error("do: neither list nor atom follows do", FALSE);
+           }
+               /* NOTREACHED */
+}
+
+lispval
+Nprogv()
+{
+       register lispval where, handy;
+       register struct nament *namptr;
+       register struct argent *vars;
+       struct nament *oldbnp = bnp;
+       Savestack(4);
+
+       where = lbot->val;
+       protect(eval(where->d.car));            /* list of vars = lbot[1].val */
+       protect(eval((where = where->d.cdr)->d.car));
+                                               /* list of vals */
+       handy = lbot[2].val;
+       namptr = oldbnp;
+                                               /* simultaneous eval of all
+                                                  args */
+       for(;handy!=nil; handy = handy->d.cdr) {
+               (np++)->val = (handy->d.car);
+               /*  Note, each element should not be reevaluated like it 
+                *  was  before.  - dhl */
+               /* Before: (np++)->val = eval(handy->d.car);*/
+               TNP;
+       }
+       /*asm("# Here is where rebinding is done");      /* very cute */
+       for(handy=lbot[1].val,vars=lbot+3; handy!=nil; handy=handy->d.cdr) {
+           namptr->atm = handy->d.car;
+           ++namptr;                           /* protect against interrupts
+                                                  while re-lambda binding */
+           bnp = namptr;
+           namptr[-1].atm = handy->d.car;
+           namptr[-1].val = handy->d.car->a.clb;
+           if(vars < np)
+               handy->d.car->a.clb = vars++->val;
+           else
+               handy->d.car->a.clb = nil;
+       }
+               
+       handy = nil;
+       for(where = where->d.cdr; where != nil; where = where->d.cdr)
+               handy = eval(where->d.car);
+       popnames(oldbnp);
+       Restorestack();
+       return(handy);
+}
+
+lispval
+Nprogn()
+{
+       register lispval result, where;
+
+       result = nil;
+       for(where = lbot->val; where != nil; where = where->d.cdr)
+               result = eval(where->d.car);
+       return(result);
+
+
+}
+lispval
+Nprog2()
+{
+       register lispval result, where;
+
+       where = lbot->val; 
+       eval(where->d.car);
+       result = eval((where = where->d.cdr)->d.car);
+       protect(result);
+       for(where = where->d.cdr; where != nil; where = where->d.cdr)
+               eval(where->d.car);
+       np--;
+       return(result);
+}
+lispval
+typred(typ,ptr)
+int    typ;
+lispval        ptr;
+
+{   int tx;
+       if ((tx = TYPE(ptr)) == typ) return(tatom);
+       if ((tx == INT) && (typ == ATOM)) return(tatom);
+       return(nil);
+}
+
+/*
+ * function
+ * In the interpreter, function is the same as quote
+ */
+lispval
+Nfunction()
+{
+       if((lbot->val == nil) || (lbot->val->d.cdr != nil))
+               argerr("function");
+       return(lbot->val->d.car);
+}
diff --git a/usr/src/ucb/lisp/franz/fex3.c b/usr/src/ucb/lisp/franz/fex3.c
new file mode 100644 (file)
index 0000000..bd51829
--- /dev/null
@@ -0,0 +1,523 @@
+#ifndef lint
+static char *rcsid = "$Header: /na/franz/franz/RCS/fex3.c,v 1.12 83/08/22 19:28:06 sklower Exp $";
+#endif
+/*                                     -[Sat Apr  9 17:03:02 1983 by layer]-
+ *     fex3.c                          $Locker:  $
+ * nlambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+extern char *gstab();
+static int pagsiz, pagrnd;
+
+
+/*
+ *Ndumplisp -- create executable version of current state of this lisp.
+ */
+#ifndef        os_vms
+#include "aout.h"
+
+lispval
+Ndumplisp()
+{
+       register struct exec *workp;
+       register lispval argptr, temp;
+       register char *fname;
+       extern int reborn;
+       struct exec work, old;
+       extern int dmpmode,usehole;
+       extern char etext[], *curhbeg;
+       int descrip, des2, ax,mode;
+       extern int holesize;
+       char tbuf[BUFSIZ];
+       long count, lseek();
+
+
+       pageseql();
+       pagsiz = Igtpgsz();
+       pagrnd = pagsiz - 1;
+
+       /* dump mode is kept in decimal (which looks like octal in dmpmode)
+          and is changeable via (sstatus dumpmode n) where n is 413 or 410
+          base 10              
+       */
+       if(dmpmode == 413) mode = 0413;
+       else mode = 0410;
+
+       workp = &work;
+       workp->a_magic  = mode;
+       if(holesize) {  /* was ifdef HOLE */
+               curhbeg         = (char *) (1 + (pagrnd | ((int)curhbeg)-1));
+               workp->a_text   = (unsigned long)curhbeg - (unsigned long)OFFSET;
+               workp->a_data   = (unsigned) sbrk(0) - workp->a_text - OFFSET;
+       } else {
+               workp->a_text   = 1 + ((((int)etext)-1-OFFSET) | pagrnd);
+               workp->a_data   = (int) sbrk(0) - ((int)curhbeg);
+       }
+       workp->a_bss    = 0;
+       workp->a_syms   = 0;
+       workp->a_entry  = (unsigned) gstart();
+       workp->a_trsize = 0;
+       workp->a_drsize = 0;
+
+       fname = "savedlisp"; /*set defaults*/
+       reborn = (int) CNIL;
+       argptr = lbot->val;
+       if (argptr != nil) {
+               temp = argptr->d.car;
+               if((TYPE(temp))==ATOM)
+                       fname = temp->a.pname;
+       }
+       des2 = open(gstab(),0);
+       if(des2 >= 0) {
+               if(read(des2,(char *)&old,sizeof(old))>=0)
+                       work.a_syms = old.a_syms;
+       }
+       descrip=creat(fname,0777); /*doit!*/
+       if(-1==write(descrip,(char *)workp,sizeof(work)))
+       {
+               close(descrip);
+               error("Dumplisp header failed",FALSE);
+       }
+       if(mode == 0413) lseek(descrip,(long)pagsiz,0); 
+       if( -1==write(descrip,(char *)nil,(int)workp->a_text) )
+       {
+               close(descrip);
+               error("Dumplisp text failed",FALSE);
+       }
+       if( -1==write(descrip,(char *)curhbeg,(int)workp->a_data) )
+       {
+               close(descrip);
+               error("Dumplisp data failed",FALSE);
+       }
+       if(des2>0  && work.a_syms) {
+               count = old.a_text + old.a_data + (old.a_magic == 0413 ? pagsiz 
+                                                              : sizeof(old));
+               if(-1==lseek(des2,count,0))
+                       error("Could not seek to stab",FALSE);
+               for(count = old.a_syms;count > 0; count -=BUFSIZ) {
+                       ax = read(des2,tbuf,(int)(count < BUFSIZ ? count : BUFSIZ));
+                       if(ax==0) {
+                               printf("Unexpected end of syms",count);
+                               fflush(stdout);
+                               break;
+                       } else if(ax >  0)
+                               write(descrip,tbuf,ax);
+                       else 
+                               error("Failure to write dumplisp stab",FALSE);
+               }
+#if ! (os_unix_ts | os_unisoft)
+               if(-1 == lseek(des2,(long)
+                       ((old.a_magic == 0413 ? pagsiz : sizeof(old))
+                       + old.a_text + old.a_data
+                               + old.a_trsize + old.a_drsize + old.a_syms),
+                              0))
+                       error(" Could not seek to string table ",FALSE);
+               for( ax = 1 ; ax > 0;) {
+                    ax = read(des2,tbuf,BUFSIZ);
+                    if(ax > 0)
+                        write(descrip,tbuf,ax);
+                    else if (ax < 0)
+                        error("Error in string table read ",FALSE);
+               }
+#endif
+       }
+       close(descrip);
+       if(des2>0) close(des2);
+       reborn = 0;
+
+       pagenorm();
+
+       return(nil);
+}
+
+\f
+/*** VMS version of Ndumplisp ***/
+#else
+#include "aout.h"
+#undef protect
+#include <vms/vmsexe.h>
+
+lispval
+Ndumplisp()
+{
+       register struct exec *workp;
+       register lispval argptr, temp;
+       char *fname;
+       register ISD *Isd;
+       register int i;
+       extern lispval reborn;
+       struct exec work,old;
+       extern etext;
+       extern int dmpmode,holend,curhbeg,usehole,holesize;
+       int extra_cref_page = 0;
+       char *start_of_data;
+       int descrip, des2, count, ax,mode;
+       char buf[5000],stabname[100],tbuf[BUFSIZ];
+       int fp,fp1;
+       union {
+               char Buffer[512];
+               struct {
+                       IHD Ihd;
+                       IHA Iha;
+                       IHS Ihs;
+                       IHI Ihi;
+                       } Header;
+               } Buffer;       /* VMS Header */
+
+       /*
+        *      Dumpmode is always 413!!
+        */
+       mode = 0413;
+       pagsiz = Igtpgsz();
+       pagrnd = pagsiz - 1;
+
+       workp = &work;
+       workp->a_magic   = mode;
+       if (holesize) {
+               workp->a_text   =
+                       ((unsigned)curhbeg) & (~pagrnd);
+               if (((unsigned)curhbeg) & pagrnd) extra_cref_page = 1;
+               start_of_data = (char *)
+                       (((((unsigned) (&holend)) -1) & (~pagrnd)) + pagsiz);
+       } else {
+               workp->a_text   =
+                       ((((unsigned) (&etext)) -1) & (~pagrnd)) + pagsiz;
+               start_of_data = (char *)workp->a_text;
+       }
+       workp->a_data   =
+               (unsigned) sbrk(0) - (unsigned)start_of_data;
+       workp->a_bss    = 0;
+       workp->a_syms   = 0;
+       workp->a_entry  = (unsigned) gstart();
+       workp->a_trsize = 0;
+       workp->a_drsize = 0;
+
+       fname = "savedlisp";    /* set defaults */
+       reborn = CNIL;
+       argptr = lbot->val;
+       if (argptr != nil) {
+               temp = argptr->d.car;
+               if((TYPE(temp))==ATOM)
+                       fname = temp->a.pname;
+       }
+       /*
+        *      Open the new executable file
+        */
+       strcpy(buf,fname);
+       if (index(buf,'.') == 0) strcat(buf,".exe");
+       if ((descrip = creat(buf,0777)) < 0) error("Dumplisp failed",FALSE);
+       /*
+        *      Create the VMS header
+        */
+       for(i = 0; i < 512; i++) Buffer.Buffer[i] = 0;  /* Clear Header */
+       Buffer.Header.Ihd.size          = sizeof(Buffer.Header);
+       Buffer.Header.Ihd.activoff      = sizeof(IHD);
+       Buffer.Header.Ihd.symdbgoff     = sizeof(IHD) + sizeof(IHA);
+       Buffer.Header.Ihd.imgidoff      = sizeof(IHD) + sizeof(IHA) + sizeof(IHS);
+       Buffer.Header.Ihd.majorid[0]    = '0';
+       Buffer.Header.Ihd.majorid[1]    = '2';
+       Buffer.Header.Ihd.minorid[0]    = '0';
+       Buffer.Header.Ihd.minorid[1]    = '2';
+       Buffer.Header.Ihd.imgtype       = IHD_EXECUTABLE;
+       Buffer.Header.Ihd.privreqs[0]   = -1;
+       Buffer.Header.Ihd.privreqs[1]   = -1;
+       Buffer.Header.Ihd.lnkflags.nopobufs = 1;
+       Buffer.Header.Ihd.imgiocnt = 250;
+
+       Buffer.Header.Iha.tfradr1       = SYS$IMGSTA;
+       Buffer.Header.Iha.tfradr2       = workp->a_entry;
+
+       strcpy(Buffer.Header.Ihi.imgnam+1,"SAVEDLISP");
+       Buffer.Header.Ihi.imgnam[0] = 9;
+       Buffer.Header.Ihi.imgid[0] = 0;
+       Buffer.Header.Ihi.imgid[1] = '0';
+       sys$gettim(Buffer.Header.Ihi.linktime);
+       strcpy(Buffer.Header.Ihi.linkid+1," Opus 38");
+       Buffer.Header.Ihi.linkid[0] = 8;
+
+       Isd = (ISD *)&Buffer.Buffer[sizeof(Buffer.Header)];
+               /* Text ISD */
+       Isd->size       = ISDSIZE_TEXT;
+       Isd->pagcnt     = workp->a_text >> 9;
+       Isd->vpnpfc.vpn = 0;
+       Isd->flags.type = ISD_NORMAL;
+       Isd->vbn        = 3;
+       Isd = (ISD *)((char *)Isd + Isd->size);
+               /* Hole ISDs (if necessary) */
+       if (usehole) {
+               /* Copy on Ref ISD for possible extra text page */
+               if(extra_cref_page) {
+                       Isd->size       = ISDSIZE_TEXT;
+                       Isd->pagcnt     = 1;
+                       Isd->vpnpfc.vpn = (((unsigned)curhbeg) & (~pagrnd)) >> 9;
+                       Isd->flags.type = ISD_NORMAL;
+                       Isd->flags.crf  = 1;
+                       Isd->flags.wrt  = 1;
+                       Isd->vbn        = (workp->a_text >> 9) + 3;
+                       Isd = (ISD *)((char *)Isd + Isd->size);
+               }
+               /* Demand Zero ISD for rest of Hole */
+               Isd->size       = ISDSIZE_DZRO;
+               Isd->pagcnt     =
+                       ((((unsigned)&holend)
+                               - (unsigned)curhbeg) & (~pagrnd)) >> 9;
+               Isd->vpnpfc.vpn =
+                       ((((unsigned)curhbeg) & (~pagrnd)) >> 9) + extra_cref_page;
+               Isd->flags.type = ISD_NORMAL;
+               Isd->flags.dzro = 1;
+               Isd->flags.wrt  = 1;
+               Isd = (ISD *)((char *)Isd + Isd->size);
+       }
+               /* Data ISD */
+       Isd->size       = ISDSIZE_TEXT;
+       Isd->pagcnt     = workp->a_data >> 9;
+       Isd->vpnpfc.vpn = ((unsigned)start_of_data) >> 9;
+       Isd->flags.type = ISD_NORMAL;
+       Isd->flags.crf  = 1;
+       Isd->flags.wrt  = 1;
+       Isd->vbn        = (workp->a_text >> 9) + 3;
+       if (holesize) {
+               /*
+                *      Correct the Data ISD
+                */
+               Isd->vbn        += extra_cref_page;
+       }
+       Isd = (ISD *)((char *)Isd + Isd->size);
+               /* Stack ISD */
+       Isd->size       = ISDSIZE_DZRO;
+       Isd->pagcnt     = ISDSTACK_SIZE;
+       Isd->vpnpfc.vpn = ISDSTACK_BASE;
+       Isd->flags.type = ISD_USERSTACK;
+       Isd->flags.dzro = 1;
+       Isd->flags.wrt  = 1;
+       Isd = (ISD *)((char *)Isd + Isd->size);
+               /* End of ISD List */
+       Isd->size = 0;
+       Isd = (ISD *)((char *)Isd + 2);
+       /*
+        *      Make the rest of the header -1s
+        */
+       for (i = ((char *)Isd - Buffer.Buffer); i < 512; i++)
+                                               Buffer.Buffer[i] = -1;
+       /*
+        *      Write the VMS Header
+        */
+       if (write(descrip,Buffer.Buffer,512) == -1)
+                                       error("Dumplisp failed",FALSE);
+#if    EUNICE_UNIX_OBJECT_FILE_CFASL
+       /*
+        *      Get the UNIX symbol table file header
+        */
+       des2 = open(gstab(),0);
+       if (des2 >= 0) {
+               old.a_magic = 0;
+               if (read(des2,(char *)&old,sizeof(old)) >= 0) {
+                       if (N_BADMAG(old)) {
+                               lseek(des2,512,0);      /* Try block #1 */
+                               read(des2,(char *)&old,sizeof(old));
+                       }
+                       if (!N_BADMAG(old)) work.a_syms = old.a_syms;
+               }
+       }
+#endif EUNICE_UNIX_OBJECT_FILE_CFASL
+       /*
+        *      Update the UNIX header so that the extra cref page is
+        *      considered part of data space.
+        */
+       if (extra_cref_page) work.a_data += 512;
+       /*
+        *      Write the UNIX header
+        */
+       if (write(descrip,&work,sizeof(work)) == -1)
+                               error("Dumplisp failed",FALSE);
+       /*
+        *      seek to 1024 (end of headers)
+        */
+       if (lseek(descrip,1024,0) == -1)
+                               error("Dumplisp failed",FALSE);
+       /*
+        *      write the world
+        */
+       if (write(descrip,0,workp->a_text) == -1)
+                               error("Dumplisp failed",FALSE);
+       if (extra_cref_page)
+               if (write(descrip,(((unsigned)curhbeg) & pagrnd), pagsiz) == -1)
+                               error("Dumplisp failed",FALSE);
+       if (write(descrip,start_of_data,workp->a_data) == -1)
+                               error("Dumplisp failed",FALSE);
+
+#if    !EUNICE_UNIX_OBJECT_FILE_CFASL
+       /*
+        *      VMS OBJECT files: We are done with the executable file
+        */
+       close(descrip);
+       /*
+        *      Now try to write the symbol table file!
+        */
+       strcpy(buf,gstab());
+
+       strcpy(stabname,fname);
+       if (index(stabname,'.') == 0) strcat(stabname,".stb");
+       else strcpy(index(stabname,'.'), ".stb");
+
+       /* Use Link/Unlink to rename the symbol table */
+       if (!strcmpn(gstab(),"tmp:",4))
+               if (link(buf,stabname) >= 0)
+                       if (unlink(buf) >= 0) return(nil);
+
+       /* Copy the symbol table */
+       if ((fp  = open(buf,0)) < 0)
+                       error("Symbol table file not there\n",FALSE);
+       fp1 = creat(stabname,0666,"var");
+       while((i = read(fp,buf,5000)) > 0)
+               if (write(fp1,buf,i) == -1) {
+                       close(fp); close(fp1);
+                       error("Error writing symbol table\n",FALSE);
+               }
+       close(fp); close(fp1);
+       if (i < 0) error("Error reading symbol table\n",FALSE);
+       if (!strcmpn(gstab(),"tmp:",4)) unlink(gstab);
+       /*
+        *      Done
+        */
+       reborn = 0;
+       return(nil);
+#else  EUNICE_UNIX_OBJECT_FILE_CFASL
+       /*
+        *      UNIX OBJECT files: append the new symbol table
+        */
+       if(des2>0  && work.a_syms) {
+               count = old.a_text + old.a_data + (old.a_magic == 0413 ? 1024
+                                                              : sizeof(old));
+               if(-1==lseek(des2,count,0))
+                       error("Could not seek to stab",FALSE);
+               for(count = old.a_syms;count > 0; count -=BUFSIZ) {
+                       ax = read(des2,tbuf,(int)(count < BUFSIZ ? count : BUFSIZ));
+                       if(ax==0) {
+                               printf("Unexpected end of syms",count);
+                               fflush(stdout);
+                               break;
+                       } else if(ax >  0)
+                               write(descrip,tbuf,ax);
+                       else 
+                               error("Failure to write dumplisp stab",FALSE);
+               }
+               if(-1 == lseek(des2,(long)
+                       ((old.a_magic == 0413 ? 1024 : sizeof(old))
+                       + old.a_text + old.a_data
+                               + old.a_trsize + old.a_drsize + old.a_syms),
+                              0))
+                       error(" Could not seek to string table ",FALSE);
+               for( ax = 1 ; ax > 0;) {
+                    ax = read(des2,tbuf,BUFSIZ);
+                    if(ax > 0)
+                        write(descrip,tbuf,ax);
+                    else if (ax < 0)
+                        error("Error in string table read ",FALSE);
+               }
+       }
+       close(descrip);
+       if(des2>0) close(des2);
+       reborn = 0;
+
+       return(nil);
+#endif EUNICE_UNIX_OBJECT_FILE_CFASL
+}
+#endif
+#if (os_4_1 | os_4_1a | os_4_1c | os_4_2)
+
+#ifdef os_4_2
+#include <sys/vadvise.h>
+#else
+#include <vadvise.h>
+#endif
+
+pagerand() { vadvise(VA_ANOM); }
+pageseql() { vadvise(VA_SEQL); }
+pagenorm() { vadvise(VA_NORM); }
+#endif
+#if (os_unisoft | os_vms)
+pagerand() { }
+pageseql() { }
+pagenorm() { }
+#endif
+
+/* getaddress --
+ *
+ * (getaddress '|_entry1| 'fncname1 '|_entry2| 'fncname2 ...)
+ *
+ * binds value of symbol |_entry1| to function defition of atom fncname1, etc.
+ *
+ * returns fnc-binding of fncname1.
+ *
+ */
+#if os_unisoft || os_unix_ts
+#define N_name n_name
+#define STASSGN(p,q) strncpy(NTABLE[(p)].n_name,(q),8)
+#else
+#define N_name n_un.n_name
+#define STASSGN(p,q) (NTABLE[p].N_name = (q))
+#endif
+
+lispval
+Lgetaddress(){
+       register struct argent *mlbot = lbot;
+       register lispval work;
+       register int numberofargs, i;
+       char ostabf[128];
+       struct nlist NTABLE[100];
+       lispval dispget();
+
+       Savestack(4);
+
+       if(np-lbot == 2) protect(nil);  /* allow 2 args */
+       numberofargs = (np - lbot)/3;
+       if(numberofargs * 3 != np-lbot)
+          error("getaddress: arguments must come in triples ",FALSE);
+
+       for ( i=0; i<numberofargs; i++,mlbot += 3) {
+               NTABLE[i].n_value = 0;
+               mlbot[0].val = verify(mlbot[0].val,"Incorrect entry specification for binding");
+               STASSGN(i,(char *) mlbot[0].val);
+               while(TYPE(mlbot[1].val) != ATOM)
+                       mlbot[1].val = errorh1(Vermisc,
+                                       "Bad associated atom name for binding",
+                                         nil,TRUE,0,mlbot[1].val);
+               mlbot[2].val = dispget(mlbot[2].val,"getaddress: Incorrect discipline specification ",(lispval)Vsubrou->a.pname);
+       }
+               STASSGN(numberofargs,"");
+       strcpyn(ostabf,gstab(),128);
+       if ( nlist(ostabf,NTABLE) == -1 ) {
+           errorh1(Vermisc,"Getaddress: Bad file",nil,FALSE,0,inewstr(ostabf));
+       } else 
+           for (i=0,mlbot=lbot+1; i<numberofargs; i++,mlbot+=3) {
+               if ( NTABLE[i].n_value == 0 )
+                   fprintf(stderr,"Undefined symbol: %s\n",
+                             NTABLE[i].N_name);
+               else {
+                   work= newfunct();
+                   work->bcd.start = (lispval (*) ())NTABLE[i].n_value;
+                   work->bcd.discipline = mlbot[1].val;
+                   mlbot->val->a.fnbnd = work;
+               }
+           };
+       Restorestack();
+       return(lbot[1].val->a.fnbnd);
+};
+
+Igtpgsz()
+{
+#if os_4_1c | os_4_2
+       return(getpagesize());
+#else
+#if vax_eunice_vms | os_unisoft
+       return(512);
+#else
+       return(1024);
+#endif
+#endif
+}
diff --git a/usr/src/ucb/lisp/franz/ffasl.c b/usr/src/ucb/lisp/franz/ffasl.c
new file mode 100644 (file)
index 0000000..d15612b
--- /dev/null
@@ -0,0 +1,604 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: ffasl.c,v 1.9 83/09/12 14:17:21 sklower Exp $";
+#endif
+
+/*                                     -[Mon Mar 21 19:37:21 1983 by jkf]-
+ *     ffasl.c                         $Locker:  $
+ * dynamically load C code
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <aout.h>
+#define round(x,s) ((((x)-1) & ~((s)-1)) + (s))
+
+char *stabf = 0, *strcpy(), *sprintf(), *Ilibdir();
+extern int fvirgin;
+static seed=0, mypid = 0;
+static char myname[100];
+lispval verify();
+
+/* dispget - get discipline of function
+ * this is used to handle the tricky defaulting of the discipline
+ * field of such functions as cfasl and getaddress.
+ * dispget is given the value supplied by the caller,
+ *     the error message to print if something goes wrong,
+ *     the default to use if nil was supplied.
+ * the discipline can be an atom or string.  If an atom it is supplied
+ * it must be lambda, nlambda or macro.  Otherwise the atoms pname
+ * is used.
+ */
+
+lispval 
+dispget(given,messg,defult)
+lispval given,defult;
+char *messg;
+{
+       int typ;
+
+       while(TRUE)
+       {
+               if(given == nil) 
+                  return(defult);
+               if((typ=TYPE(given)) == ATOM)
+               {  if(given == lambda ||
+                     given == nlambda ||
+                     given == macro) return(given);
+                  else return((lispval) given->a.pname);
+               } else if(typ == STRNG) return(given);
+
+               given = errorh1(Vermisc,messg,nil,TRUE,0,given);
+       }
+}
+
+lispval
+Lcfasl(){
+       register struct argent *mlbot = lbot;
+       register lispval work;
+       register int fildes, totsize;
+       int readsize;
+       lispval csegment();
+       char *sbrk(), *currend, *tfile, cbuf[6000], *mytemp(), *gstab();
+       char ostabf[128];
+       struct exec header;
+       char *largs;
+       Savestack(4);
+
+       switch(np-lbot) {
+          case 3: protect(nil);        /* no discipline given */
+          case 4: protect(nil);        /* no library given  */
+       }
+       chkarg(5,"cfasl");
+       mlbot[0].val = verify(mlbot[0].val,"Incorrect .o file specification");
+       mlbot[1].val = verify(mlbot[1].val,"Incorrect entry specification for cfasl");
+       mlbot[3].val = dispget(mlbot[3].val,"Incorrect discipline specification for cfasl",(lispval)Vsubrou->a.pname);
+       while(TYPE(mlbot[2].val)!= ATOM) 
+       mlbot[2].val = errorh1(Vermisc,"Bad associated atom name for fasl",
+                                                nil,TRUE,0,mlbot[2].val);
+       work = mlbot[4].val;
+       if(work==nil)
+               largs = 0;
+       else 
+               largs = (char *) verify(work,"Bad loader flags");
+
+       /*
+        * Invoke loader.
+        */
+       strcpy(ostabf,gstab());
+       currend = sbrk(0);
+#if (!os_vms) | EUNICE_UNIX_OBJECT_FILE_CFASL
+                       /*** UNIX cfasl code ***/
+       tfile = mytemp();
+       sprintf(cbuf,
+               "%s/nld -N -x -A %s -T %x %s -e %s -o %s %s -lc",
+               Ilibdir(),
+               ostabf,
+               currend,
+               mlbot[0].val,
+               mlbot[1].val,
+               tfile,
+               largs);
+       /* if nil don't print cfasl/nld message */
+       if ( Vldprt->a.clb != nil ) {
+               printf(cbuf);
+               putchar('\n'); fflush(stdout);
+       }
+       if(system(cbuf)!=0) {
+               unlink(tfile);
+               ungstab();
+               fprintf(stderr,"Ld returns error status\n");
+               Restorestack();
+               return(nil);
+       }
+       if(fvirgin)
+               fvirgin = 0;
+       else
+               unlink(ostabf);
+       stabf = tfile;
+       if((fildes = open(tfile,0))<0) {
+               fprintf(stderr,"Couldn't open temporary file: %s\n",tfile);
+               Restorestack();
+               return(nil);
+       }
+       /*
+        * Read a.out header to find out how much room to
+        * allocate and attempt to do so.
+        */
+       if(read(fildes,(char *)&header,sizeof(header)) <= 0) {
+               close(fildes);
+               Restorestack();
+               return(nil);
+       }
+       readsize = round(header.a_text,4) + round(header.a_data,4);
+       totsize  = readsize + header.a_bss;
+       totsize  = round(totsize,512);
+       /*
+        * Fix up system indicators, typing info, etc.
+        */
+       currend = (char *)csegment(OTHER,totsize,FALSE);
+       
+       if(readsize!=read(fildes,currend,readsize))
+               {close(fildes);Restorestack(); return(nil);}
+       work = newfunct();
+       work->bcd.start = (lispval (*)())header.a_entry;
+       work->bcd.discipline = mlbot[3].val;
+       close(fildes);
+       Restorestack();
+       return(mlbot[2].val->a.fnbnd = work);
+#else
+                       /*** VMS cfasl code ***/
+       {
+         int pid = getpid() & 0xffff;  /* Our process ID number */
+         char objfil[100];             /* Absolute object file name */
+         char symfil[100];             /* Old symbol table file */
+         char filename[100];           /* Random filename buffer */
+         int strlen();                 /* String length function */
+         int cvt_unix_to_vms();        /* Convert UNIX to VMS filename */
+         lispval Lgetaddress(),matom();
+         struct stat stbuf;
+
+         if (largs == 0) largs = " ";
+         sprintf(objfil,"tmp:cfasl%d.tmp",pid);
+         symfil[cvt_unix_to_vms(ostabf,symfil)] = 0;
+         sprintf(cbuf,                                 /* Create link cmd. */
+               "$ link/exe=%s/nom/syst=%%X%x/sym=tmp:sym%d.new %s,%s%s",
+               objfil,
+               currend,
+               pid,
+               mlbot[0].val,
+               symfil,
+               largs);
+         printf(                                       /* Echo link cmd. */
+               "$ link/exe=%s/nomap/system=%%X%x/symbol_table=tmp:sym%d.new %s,%s%s\n",
+               objfil,
+               currend,
+               pid,
+               mlbot[0].val,
+               symfil,
+               largs);
+         fflush(stdout);
+         vms_system(cbuf,0);
+
+         if ((fildes = open(objfil,0)) < 0) /* Open abs file */
+               {Restorestack(); return(nil);}
+         fstat(fildes,&stbuf);                         /* Get its size */
+         readsize=stbuf.st_size;
+         currend = (char *)csegment(OTHER,readsize,FALSE);
+         readsize = read(fildes,currend,10000000);
+         close(fildes);
+         /*
+          * Delete the absolute object file
+          */
+         unlink(objfil);
+         /*
+          * Delete the old symbol table (if temporary)
+          */
+         unlink(sprintf(filename,"tmp:sym%d.stb",pid));
+         /*
+          * Rename the new symbol table so it is now the old symbol table
+          */
+         link(sprintf(symfil,"tmp:sym%d.new",pid),filename);
+         unlink(symfil);
+         sprintf(myname,"tmp:sym%d.stb",pid);
+         stabf = myname;
+         /*
+          * Return  Lgetaddress(entry,function_name,discipline)
+          */
+         {
+            struct argent *oldlbot, *oldnp;
+            lispval result;
+
+            oldlbot = lbot;
+            oldnp = np;
+            lbot = np;
+            np++->val = matom(mlbot[1].val);
+            np++->val = mlbot[2].val;
+            np++->val = matom(mlbot[3].val);
+            result = Lgetaddress();
+            lbot = oldlbot;
+            np = oldnp;
+            return(result);
+         }
+       }
+#endif
+}
+#ifdef os_vms
+#define M 4
+#else
+#define M 1
+#endif
+#define oktox(n) \
+       (0==stat(n,&stbuf)&&(stbuf.st_mode&S_IFMT)==S_IFREG&&0==access(n,M))
+char *
+gstab()
+{
+       register char *cp, *cp2; char *getenv();
+       struct stat stbuf;
+       extern char **Xargv;
+
+       if(stabf==0) {
+               cp = getenv("PATH");
+               if(cp==0)
+                       cp=":/usr/ucb:/bin:/usr/bin";
+               if(*cp==':'||*Xargv[0]=='/') {
+                       cp++;
+                       if(oktox(Xargv[0])) {
+                               strcpy(myname,Xargv[0]);
+                               return(stabf = myname);
+                       }
+#ifdef os_vms
+                       /*
+                        *      Try Xargv[0] with ".stb" concatenated
+                        */
+                       strcpy(myname,Xargv[0]);
+                       strcat(myname,".stb");
+                       if (oktox(myname)) return(stabf = myname);
+                       /*
+                        *      Try Xargv[0] with ".exe" concatenated
+                        */
+                       strcpy(myname,Xargv[0]);
+                       strcat(myname,".exe");
+                       if (oktox(myname)) return(stabf = myname);
+#endif
+               }
+               for(;*cp;) {
+
+                       /* copy over current directory
+                          and then append argv[0] */
+
+                       for(cp2=myname;(*cp)!=0 && (*cp)!=':';)
+                               *cp2++ = *cp++;
+                       *cp2++ = '/';
+                       strcpy(cp2,Xargv[0]);
+                       if(*cp) cp++;
+#ifndef        os_vms
+                       if(!oktox(myname)) continue;
+#else
+                       /*
+                        *      Also try ".stb" and ".exe" in VMS
+                        */
+                       if(!oktox(myname)) {
+                               char *end_of_name;
+                               end_of_name = cp2 + strlen(cp2);
+                               strcat(cp2,".stb");
+                               if(!oktox(myname)) {
+                                       /*
+                                        *      Try ".exe"
+                                        */
+                                       *end_of_name = 0;   /* Kill ".stb" */
+                                       strcat(cp2,".exe");
+                                       if (!oktox(myname)) continue;
+                               }
+                       }
+#endif
+                       return(stabf = myname);
+               }
+               /* one last try for dual systems */
+               strcpy(myname,Xargv[0]);
+               if(oktox(myname)) return(stabf = myname);
+               error("Could not find which file is being executed.",FALSE);
+               /* NOTREACHED */
+       } else return (stabf);
+}
+static char mybuff[40]; 
+char *
+mytemp()
+{
+       /*if(mypid==0) mypid = (getpid() & 0xffff);
+         fails if you do a dumplisp after doing a
+         cfasl */
+       sprintf(mybuff,"/tmp/Li%d.%d",(getpid() & 0xffff),seed++);
+       return(mybuff);
+}
+ungstab()
+{
+       seed--;
+       sprintf(mybuff,"/tmp/Li%d.%d",(getpid() & 0xffff),seed-1);
+       if(seed==0) {
+               stabf = 0;
+               fvirgin = 1;
+       }
+}
+lispval
+verify(in,error)
+register lispval in;
+char *error;
+{
+       for(EVER) {
+               switch(TYPE(in)) {
+               case STRNG:
+                       return(in);
+               case ATOM:
+                       return((lispval)in->a.pname);
+               }
+               in = errorh1(Vermisc,error,nil,TRUE,0,in);
+       }
+}
+
+
+/* extern      int fvirgin; */
+                       /* declared in ffasl.c tells if this is original
+                        *      lisp symbol table.
+                        * if fvirgin is 1 then we must copy the symbol
+                        *      table, else we can overwrite it, since
+                        *      it is a temporary file which only
+                        *      one user could be using(was not created
+                        *      as an original lisp or by a (dumplisp)
+                        *      or a (savelisp)).
+                        */
+
+/* copy a block of data from one file to another of size size */
+copyblock(f1,f2,size)
+FILE *f1, *f2;
+long size;
+{
+       char block[BUFSIZ];
+
+           while ( size > BUFSIZ ) {
+               size -= BUFSIZ;
+               fread(block,BUFSIZ,1,f1);
+               fwrite(block,BUFSIZ,1,f2);
+           }
+           if (size > 0 ) {
+               fread(block,(int)size,1,f1);
+               fwrite(block,(int)size,1,f2);
+           }
+}
+
+/* removeaddress --
+ *
+ * (removeaddress '|_entry1| '|_entry2| ...)
+ *
+ *     removes the given entry points from the run time symbol table,
+ *             so that later cfasl'd files can have these label names.
+ *
+ */
+
+lispval
+Lrmadd(){
+       register struct argent *mlbot = lbot;
+       register struct nlist *q; 
+       register int i;
+       int numberofargs, strsize;
+       char *gstab();
+       char ostabf[128];
+       char *nstabf,*mytemp();
+       char *strtbl,*alloca();
+       int i2, n, m, nargleft, savem;
+       FILE *f, *fa;
+       FILE *fnew;
+       off_t savesymadd,symadd;                /* symbol address */
+       struct exec buf;
+       struct nlist nlbuf[BUFSIZ/sizeof (struct nlist)];
+       int maxlen;
+       int change;
+       Keepxs();
+
+       numberofargs = (np - lbot);
+       nargleft = numberofargs;
+       maxlen = 0;
+       for ( i=0; i<numberofargs; i++,mlbot ++) {
+               mlbot->val = verify(mlbot->val,"Incorrect entry specification.");
+               n = strlen((char *)mlbot->val);
+               if (n > maxlen)
+                       maxlen = n;
+       }
+       /* 
+        *  Must not disturb object file if it an original file which
+        *      other users can execute(signified by the variable fvirgin).
+        *      so the entire symbol table is copied to a new file.
+        */
+       if (fvirgin) {
+               strcpyn(ostabf,gstab(),128);
+               nstabf = mytemp();
+               /*
+                * copy over symbol table into a temporary file first
+                *
+                */
+               f = fopen(ostabf, "r");
+               fnew = fopen(nstabf, "w");
+               if (( f == NULL ) || (fnew == NULL)) {Freexs(); return( nil );}
+               /* read exec header on file */
+#ifndef        os_vms
+               fread((char *)&buf, sizeof buf, 1, f);
+#else  os_vms
+               /*
+                *      Under VMS/EUNICE we have to try the 1st 512 byte
+                *      block and the 2nd 512 byte block (there may be
+                *      a VMS header in the 1st 512 bytes).
+                */
+               get_aout_header(fileno(f),&buf);
+#endif os_vms
+
+               /* Is this a legitimate a.out file? */
+               if (N_BADMAG(buf)) {
+                       unlink(nstabf);
+                       ungstab();
+                       fclose(f);
+                       fclose(fnew);
+                       errorh1(Vermisc,"Removeaddress: Bad file",nil,FALSE,0,inewstr(ostabf));
+                       {Freexs(); return(nil);}
+               }
+               /* set pointer on read file to symbol table */
+               /* must be done before the structure buf is reassigned 
+                * so that it will be accurate for the read file 
+                */
+               fseek(f,(long)N_SYMOFF(buf),0);
+               /* reset up exec header structure for new file */
+               buf.a_magic = OMAGIC;
+               buf.a_text = 0;
+               buf.a_data = 0;
+               buf.a_bss = 0;
+               buf.a_entry = 0;
+               buf.a_trsize = 0;
+               buf.a_drsize = 0;
+               fwrite((char *)&buf,
+                      sizeof buf,1,fnew);      /* write out exec header */
+               copyblock(f,fnew,(long)buf.a_syms); /* copy symbol table */
+#if ! (os_unisoft | os_unix_ts)
+               fread((char *)&strsize,
+                     sizeof (int),1,f);        /* find size of string table */
+               fwrite((char *)&strsize,
+                     sizeof (int),1,fnew);     /* find size of string table */
+               strsize -= 4;
+               strtbl = alloca(strsize);
+               fread(strtbl,strsize,1,f);      /* read and save string table*/
+               fwrite(strtbl,strsize,1,fnew);  /* copy out string table     */
+#endif
+               fclose(f);fclose(fnew);
+       } else {
+               nstabf = gstab();
+       }
+
+       /*
+        * now unset the external bits it the entry points specified.
+        */
+       f = fopen(nstabf, "r");
+       fa = fopen(nstabf, "a");
+       if (( f == NULL ) || (fa == NULL)) {
+               unlink(nstabf);
+               ungstab();
+               if (f != NULL ) fclose(f);
+               if (fa != NULL ) fclose(fa);
+               return ( nil );
+       }
+
+       /* read exec header on file */
+#ifndef        os_vms
+       fread((char *)&buf, sizeof buf, 1, f);
+#else  os_vms
+       /*
+        *      Under VMS/EUNICE we have to try the 1st 512 byte
+        *      block and the 2nd 512 byte block (there may be
+        *      a VMS header in the 1st 512 bytes).
+        */
+       get_aout_header(fileno(f),&buf);
+#endif os_vms
+
+       /* Is this a legitimate a.out file? */
+       if (N_BADMAG(buf)) {
+               if (fvirgin) {
+                       unlink(nstabf);
+                       ungstab();
+               }
+               fclose(f);
+               fclose(fa);
+               errorh1(Vermisc,"Removeaddress: Bad file",nil,FALSE,0,inewstr(ostabf));
+               {Freexs(); return(nil);}
+       } else {
+               symadd = N_SYMOFF(buf);
+#if ! (os_unisoft | os_unix_ts)
+               /*
+                * read in string table if not done during copying
+                */
+               if (fvirgin==0){
+                       fseek(f,(long)N_STROFF(buf),0);
+                       fread((char *)&strsize,sizeof (int),1,f);
+                       strsize -= 4;
+                       strtbl = alloca(strsize);
+                       fread(strtbl,strsize,1,f);
+               }
+#endif
+               n = buf.a_syms;
+               fseek(f, (long)symadd, 0);
+               while (n) {
+                       m = sizeof (nlbuf);
+                       if (n < m)
+                               m = n;
+
+                       /* read next block of symbols from a.out file */
+                       fread((char *)nlbuf, m, 1, f);
+                       savem = m;
+                       savesymadd = symadd;
+                       symadd += m;
+                       n -= m;
+                       change = 0;
+
+               /* compare block of symbols against list of entry point
+                *      names given, if a match occurs, clear the N_EXT bit
+                *      for that given symbol and signal a change.
+                */
+                       for (q = nlbuf; (m -= sizeof(struct nlist)) >= 0; q++) {
+
+              /* make sure it is external */
+                               if (
+                                   (q->n_type & N_EXT)==0
+#if ! (os_unix_ts | os_unisoft)
+                                   || q->n_un.n_strx == 0 || q->n_type & N_STAB
+#endif
+                                  )    continue;
+                       for (mlbot=lbot,i2 = 0;i2<numberofargs;i2++,mlbot++) {
+#if ! (os_unix_ts | os_unisoft)
+                               if(strcmp((char *)mlbot->val,
+                                         strtbl+q->n_un.n_strx-4)!=0)
+                                               continue;
+#else
+                               if(strcmpn((char *)mlbot->val,
+                                          q->n_name,8)!=0)
+                                               continue;
+#endif
+                               change = 1;
+                               q->n_type &= ~N_EXT;
+                               break;
+                       }
+               }
+               if ( change ) {
+                       fseek(fa,(long)savesymadd,0);
+                       fwrite((char *)nlbuf, savem, 1, fa);
+                       if (--nargleft == 0)
+                               goto alldone;
+               }
+               }
+       }
+alldone:
+       fclose(f);
+       fclose(fa);
+       if(fvirgin)
+               fvirgin = 0;
+       stabf = nstabf;
+       {Freexs(); return(tatom);}
+}
+char *
+Ilibdir()
+{
+       register lispval handy;
+tryagain:
+       handy = Vlibdir->a.clb;
+       switch(TYPE(handy)) {
+       case ATOM:
+               handy = (lispval) handy->a.pname;
+       case STRNG:
+               break;
+       default:
+               (void) error(
+"cfasl or load: lisp-library-directory not bound to string or atom",
+                               TRUE);
+               goto tryagain;
+       }
+       return((char *) handy);
+}
diff --git a/usr/src/ucb/lisp/franz/frame.c b/usr/src/ucb/lisp/franz/frame.c
new file mode 100644 (file)
index 0000000..77a71c3
--- /dev/null
@@ -0,0 +1,303 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: frame.c,v 1.2 83/05/07 23:46:38 jkf Exp $";
+#endif
+
+/*                                     -[Sat May  7 22:27:57 1983 by jkf]-
+ *     frame.c                         $Locker: sklower $
+ * non local goto handlers
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+#include "frame.h"
+
+/* 
+ * This is a collection of routines for manipulating evaluation frames.
+ * Such frames are generated to mark the state of execution at a certain
+ * spot.  They are created upon entry to prog, do, catch, errset and
+ * other misc. functions (such as eval when in *rset mode).
+ *
+ * As described in h/frame.h, each frame is identified by a class, which
+ * says who created the frame.  The global variable errp points to the
+ * first (newest) frame on the stack.  
+ * The standard way to create a frame is to say
+ *
+ *   errp = Pushframe(class,arg1,arg2);         /* create and link in new 
+ *                                         frame of give class * /
+ *
+ * poping the frame must be done explicity if the routine was not exited by
+ * a non-local goto.  This is done by 
+ *   errp = Popframe();
+ *
+ * When a frame is created, it marks the current state on the runtime stack.
+ * Execution will continues after the Pushframe call with the value of the
+ * global variable 'retval' set to 0.  Some time later control may be thrown
+ * up the stack and it will seem that Pushframe returned again.  This time
+ * retval will contain a non-zero value indicating what caused the non-local
+ * jump.  retval will have one of the values from C_???? in h/frame.h . 
+ * It will not have just of the C_???? values, it will only have a value
+ * which makes sense. For example, coming out of a Pushframe(F_CATCH,tag,nil);
+ * retval will either be 0 (initially) or C_THROW, [and in addition it will
+ * already have been determined that the tag of the catch matches the tag
+ * being thrown, [[ this does not apply to GO's and PROG tags]] ].
+ *
+ * In doing throws, goto's, returns, or errors up the stack we are always
+ * conscious of the possiblity of unwind-protect sitting between where 
+ * control starts and where it wants to get.  Thus it may be necessary
+ * to save the state of the non-local jump, give control to the unwind-protect
+ * and have it continue the non-local jump. 
+ */
+
+ /*
+  * Inonlocalgo(class, arg1, arg2) :: do a general non-local goto.
+  *            class - one of the C_???? in h/frame.h
+  *    arg1 - tag in C_THROW, C_GO; value in C_RETURN
+  *    arg2 - value in C_THROW;
+  *  this handles GO's, THROW's, RETURN's  but not errors, which have more
+  * state to throw and a lot of different things to do if there is no one
+  * to catch the error.
+  * 
+  * This routine never returns.
+  */
+
+Inonlocalgo(class, arg1, arg2)
+lispval arg1,arg2;
+{
+    struct frame *uwpframe, *Inlthrow();
+    lispval handy;
+
+    /* 
+     * scan for something to match 'class', return if nothing found, or
+     * if we must first handle an unwind protect.
+     */
+    while( uwpframe = Inlthrow(class,arg1,arg2) )
+    {
+       /* build error frame description to be use to continue this throw */
+       protect(lispretval = handy = newdot());
+       handy->d.car = Veruwpt;
+       handy = handy->d.cdr = newdot();
+       handy->d.car = inewint(class);          /* remember type */
+       handy = handy->d.cdr = newdot();
+       handy->d.car = arg1;
+       handy = handy->d.cdr = newdot();
+       handy->d.car = arg2;
+       retval = C_THROW;
+       Iretfromfr(uwpframe);
+       /* NOT REACHED */
+    }
+
+    /*
+     * nothing to go to, signal the appropriate error
+     */
+
+    switch(class)
+    {
+    case C_GO: errorh1(Vermisc, "No prog to go to with this tag ",
+                              nil,FALSE,0,arg1);
+               /* NOT REACHED */
+
+    case C_RET: errorh(Vermisc, "No prog to return from", nil, FALSE, 0);
+               /* NOT REACHED */
+
+    case C_THROW: errorh1(Vermisc, "No catch for this tag ", nil, FALSE , 0,
+                                 arg1);
+               /* NOT REACHED */
+    default: error("Internal  Inonlocalgoto error" ,FALSE);
+               /* NOT REACHED */
+    }
+}
+
+/*
+ * Inlthrow(class,arg1,arg2) :: look up the stack for a form to handle
+ * a value of 'class' being thrown.  If found, do the throw.  If an
+ * unwind-protect must be done, then return a pointer to that frame
+ * first.  If there is nothing to catch this throw, we return 0.
+ */
+
+struct frame *
+Inlthrow(class, arg1, arg2)
+lispval arg1, arg2;
+{
+    struct frame *uwpframe = (struct frame *)0;
+    struct frame *curp;
+    int pass = 1;
+
+    restart:
+       for(curp = errp; curp != (struct frame *) 0; curp = curp->olderrp)
+       {
+           switch(curp->class)
+           {
+           case F_PROG: if(class == C_RET || class == C_GO)
+                        {
+                           if(pass == 2) return(uwpframe);
+                           else 
+                           {
+                               lispretval = arg1;
+                               retval = class;
+                               Iretfromfr(curp);
+                               /* NOT REACHED */
+                           }
+                         }
+                         break;
+
+           case F_CATCH: if((pass == 1) && (curp->larg1 == Veruwpt))
+                         {
+                               uwpframe = curp;
+                               pass = 2;
+                               goto restart;
+                         }
+                         else if(class == C_THROW 
+                                       && matchtags(arg1,curp->larg1))
+                         {
+                           if(pass == 2) return(uwpframe);
+                           else 
+                           {
+                               lispretval = arg2;      /* value thrown */
+                               retval = class;
+                               Iretfromfr(curp);
+                               /* NOT REACHED */
+                           }
+                          }
+                          break;
+           
+           case F_RESET:  if(class == C_RESET)
+                          {
+                               if(pass == 2) return(uwpframe);
+                               else
+                               {
+                                   retval = class;
+                                   Iretfromfr(curp);
+                                   /* NOT REACHED */
+                               }
+                           }
+                           break;
+
+           }
+       }
+       return((struct frame *)0);   /* nobody wants it */
+}
+
+
+Iretfromfr(fram)
+register struct frame *fram;
+{
+    xpopnames(fram->svbnp);
+    qretfromfr();      /* modified in sed script to point to real function */
+    /* NOT REACHED */
+}
+
+/* matchtags :: return TRUE if there is any atom in common between the
+ * two tags.  Either tag may be an atom or an list of atoms.
+ */
+matchtags(tag1,tag2)
+lispval tag1, tag2;
+{
+    int repeat1 = FALSE;
+    int repeat2 = FALSE;
+    lispval temp1 = tag1;
+    lispval temp2 = tag2;
+    lispval t1,t2;
+
+    if(TYPE(tag1) == ATOM) 
+    {
+       t1 = tag1;
+    }
+    else {
+       t1 = tag1->d.car;
+       repeat1 = TRUE;
+    }
+
+    if(TYPE(tag2) == ATOM)
+    {
+       t2 = tag2;
+    }
+    else {
+       t2 = tag2->d.car;
+       repeat2 = TRUE;
+    }
+
+loop:
+    if(t1 == t2) return(TRUE);
+    if(repeat2) 
+    {
+       if((temp2 = temp2->d.cdr) != nil)
+       {
+           t2 = temp2->d.car;
+           goto loop;
+       }
+    }
+
+    if(repeat1)
+    {
+        if((temp1 = temp1->d.cdr) != nil)
+       {
+           t1 = temp1->d.car;
+           if(repeat2) 
+           {
+               temp2 = tag2;
+               t2 = temp2->d.car;
+               goto loop;
+           }
+           else t2 = tag2;
+           goto loop;
+        }
+    }
+    return(FALSE);
+}
+
+/*
+ * framedump :: debugging routine to print the contents of the error 
+ * frame
+ *
+ */
+lispval
+Lframedump()
+{
+    struct frame *curp;
+
+    printf("Frame dump\n");
+    for(curp = errp ; curp != (struct frame *)0 ; curp=curp->olderrp)
+    {
+       printf("at %x is ",curp);
+
+       switch(curp->class) {
+       case F_PROG: printf(" prog\n");
+                    break;
+
+       case F_CATCH:printf(" catching ");
+                    printr(curp->larg1,stdout);
+                    putchar('\n');
+                    break;
+
+       case F_RESET:printf(" reset \n");
+                    break;
+
+       case F_EVAL: printf(" eval: ");
+                    printr(curp->larg1,stdout);
+                    putchar('\n');
+                    break;
+
+       case F_FUNCALL: printf(" funcall: ");
+                    printr(curp->larg1,stdout);
+                    putchar('\n');
+                    break;
+
+       case F_TO_FORT: printf(" calling fortran:\n");
+                    break;
+
+       case F_TO_LISP: printf(" fortran calling lisp:\n");
+                    break;
+
+               
+       default:
+                    printf(" unknown: %d \n",curp->class);
+       }
+       fflush(stdout);
+    }
+    printf("End of stack\n");
+    return(nil);
+}
+
diff --git a/usr/src/ucb/lisp/franz/h/config.h b/usr/src/ucb/lisp/franz/h/config.h
new file mode 100644 (file)
index 0000000..5650b57
--- /dev/null
@@ -0,0 +1,188 @@
+/*                                     -[Thu Mar  3 15:57:51 1983 by jkf]-
+ *     config.h                        $Locker:  $
+ * configuration dependent info
+ *
+ * $Header: config.h,v 1.13 83/09/12 15:30:30 layer Exp $
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+/* 
+ * this file contains parameters which each site is likely to modify
+ * in order to personalize the configuration of Lisp at their site.
+ * The typical things to modifiy are:
+ *    [optionally] turn on GCSTRINGS
+ *    [optionally] provide a value for SITE 
+ */
+
+/*
+ * The type of machine and os this is to run on will come from
+ * the file lconf.h.  The lconf.h file is created by the shell script
+ * 'lispconf' in the directory ../..
+ * lconf.h will define exactly one of these symbols:
+ *  vax_4_2 vax_4_1c vax_4_1a vax_4_1 vax_unix_ts vax_eunice_vms
+ *  sun_4_2 sun_4_1c sun_unisoft dual_unisoft  pixel_unisoft
+ */
+#include "lconf.h"
+
+
+/* GCSTRINGS - define this if you want the garbage collector to reclaim
+ *  strings.  It is not normally set because in typical applications the
+ *  expense of collecting strings is not worth the amount of space
+ *  retrieved
+ */
+/* #define GCSTRINGS */
+
+/*
+ * set up the global defines based on the choice above
+ * the global names are
+ * machine name:  m_vax
+ *               m_68k
+ *                     m_68k_sun, m_68k_dual m_68k_pixel
+ * operating system:
+ *               os_unix
+ *                  os_4_1, os_4_1a, os_4_1c, os_4_2, os_unix_ts
+ *               os_vms
+ */
+/* first the machine */
+#if vax_4_1 || vax_4_1a || vax_4_1c || vax_4_2 || vax_unix_ts || vax_eunice_vms
+#define m_vax 1
+#endif
+
+#if sun_4_2 || sun_4_1c || sun_unisoft
+#define m_68k          1
+#define m_68k_sun      1
+#endif
+
+#if dual_unisoft
+#define m_68k          1
+#define m_68k_dual     1
+#endif
+
+#if pixel_unisoft
+#define m_68k          1
+#define m_68k_pixel    1
+#endif
+
+/* next the operating system */
+#if vax_4_1 || vax_4_1a || vax_4_1c || vax_4_2 || vax_unix_ts || m_68k
+#define os_unix                1
+#endif
+
+#if vax_4_1
+#define os_4_1         1
+#endif
+#if vax_4_1a
+#define os_4_1a                1
+#endif
+#if vax_4_1c || sun_4_1c
+#define os_4_1c        1
+#endif
+#if vax_4_2 || sun_4_2
+#define os_4_2         1
+#endif
+#if vax_unix_ts
+#define os_unix_ts     1
+#endif
+#if vax_eunice_vms
+#define os_vms         1
+#endif
+
+#if sun_unisoft || dual_unisoft || pixel_unisoft
+#define os_unisoft 1
+#endif
+
+/* MACHINE -  this is put on the (status features) list */
+#if m_68k
+#define MACHINE "68k"
+#define PORTABLE
+#endif
+
+#if m_vax
+#define MACHINE "vax"
+#define NILIS0 1
+#endif
+
+/* OFFSET -  this is the offset to the users address space. */
+/* NB: this is not necessarily tied to the hardware.  Pixel
+   informs us that when they put up 4.1 the offsetis likely
+   to change */
+
+/*
+** NILIS0 -- for any UNIX implementation in which the users
+**     address space starts at 0 (like m_vax, above). 
+**
+** NPINREG -- for the verison if lisp that keeps np and lbot in global
+**     registers.  On the 68000, there is a special `hacked' version
+**     of the C compiler that is needed to do this.
+**
+** #define NILIS0              1
+** #define NPINREG             1
+*/
+
+/*
+ * SPISFP -- this is to indicate that the stack and frame pointer
+ * are the same, or at least that you can't pull the same shenanigans
+ * as on the vax or sun by pushing error frames at the end of C
+ * frames and using alloca.  This should make life easier for
+ * a native VMS version or IBM or RIDGE or Bellmac-32.
+ * #define SPISFP 1
+ */
+
+
+#if m_vax
+#define OFFSET         0x0
+#define NPINREG                1
+#endif
+
+#if m_68k_sun
+#define OFFSET         0x8000
+#endif
+
+#if m_68k_dual
+#define OFFSET         0x800000
+#endif
+
+#if m_68k_pixel
+#define OFFSET         0x20000
+#endif
+
+
+/* OS -  this is put on the (status features) list */
+#if os_unix
+#define OS      "unix"
+#endif
+#if os_vms
+#define OS     "vms"
+#endif
+
+/* DOMAIN - this is put on the (status features) list and
+ *     is the value of (status domain)
+ */
+#define DOMAIN  "ucb"
+
+/* SITE - the name of the particular machine this lisp is running on
+ *    this value is available via (sys:gethostname).
+ *    On 4.1a systems it is possible to determine this dynamically cheaply
+ */
+#if ! (os_4_1a || os_4_1c || os_4_2)
+#define SITE    "unknown-site"
+#endif
+
+
+/*  TTSIZ is the absolute limit, in pages (both text and data), of the
+ * size to which the lisp system may grow.
+ * If you change this, you must recompile alloc.c and data.c.
+ */
+#ifdef HOLE
+#define TTSIZE 10216
+#else
+#define TTSIZE 6120
+#endif
+
+#if m_vms 
+#undef TTSIZE
+#define TTSIZE 10216
+#define FREESIZE 512 * 10000
+#endif 
diff --git a/usr/src/ucb/lisp/franz/h/frame.h b/usr/src/ucb/lisp/franz/h/frame.h
new file mode 100644 (file)
index 0000000..4efd548
--- /dev/null
@@ -0,0 +1,67 @@
+/*                                     -[Sat Jan 29 13:55:13 1983 by jkf]-
+ *     frame.h                         $Locker:  $
+ * non local goto frame definition
+ *
+ * $Header: frame.h,v 1.3 83/09/12 15:29:08 sklower Exp $
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+/* classes of frames: */
+#define F_PROG         1
+#define F_CATCH        2
+#define F_RESET        3
+#define F_EVAL         4
+#define F_FUNCALL      5
+#define F_TO_FORT      6
+#define F_TO_LISP      7
+
+/* classes of things thrown up */
+#define C_INITIAL      0
+#define C_GO           1
+#define C_RET          2
+#define C_THROW        3
+#define C_RESET        4
+#define C_FRETURN      5
+
+
+/* the evaluation frame sits on the C runtime stack.  the global variable errp
+   points to the newest frame. The base of the frame points in the middle
+   of the frame, but in such a way that above the frame base the contents
+   are the same for all implementation, and below it there are different
+   saved registers for each machine. 
+*/
+
+struct frame 
+{
+    struct argent *svlbot, *svnp;
+    struct nament *svbnp;
+    struct frame *olderrp;
+    lispval retaddr;
+    long class;
+    lispval larg1;     /* optional */
+    lispval larg2;     /* optional */
+};
+
+extern struct frame *errp, *Pushframe(), *Ipushf();
+
+/* stuff for IBM, RIDGE, DEC-VMS CC, maybe Bellmac-32
+ *
+ * The non obvious requirement is that any new function
+ * requiring a Pushframe must declare 
+ *
+ *     pbuf pb;
+ *
+ * as well.
+ */
+
+#ifdef SPISFP
+#define Pushframe(a,b,c) Ipushf(a,b,c,&pb)
+#endif
+
+
+typedef struct pframe
+{
+       long regs[16];
+       struct frame f;
+} pbuf;
diff --git a/usr/src/ucb/lisp/franz/h/global.h b/usr/src/ucb/lisp/franz/h/global.h
new file mode 100644 (file)
index 0000000..f8f87ad
--- /dev/null
@@ -0,0 +1,439 @@
+/*                                     -[Sun Jun 19 14:42:59 1983 by jkf]-
+ *     global.h                        $Locker:  $
+ * main include file 
+ *
+ * $Header: global.h,v 1.9 83/09/12 15:27:22 sklower Exp $
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include <stdio.h>
+#include "config.h"
+#include "ltypes.h"
+#ifdef UNIXTS
+#include "tsfix.h"
+#endif
+
+#define AD 0
+
+#define        peekc(p)        (p->_cnt>0? *(p)->_ptr&0377:_filbuf(p)==-1?-1:((p)->_cnt++,*--(p)->_ptr&0377))
+
+#define FALSE  0
+#define        TRUE    1
+#define EVER   ;;
+#define STRBLEN 512
+#define LBPG   512
+
+
+#define        NULL_CHAR       0
+#define        LF      '\n'
+#define        WILDCHR '\0177'
+
+
+/* the numbers per page of the different data objects *******************/
+
+#define NUMSPACES (VECTORI+1)
+
+#define ATOMSPP 25
+#define STRSPP 1
+#define INTSPP 128
+#define DTPRSPP 64
+#define DOUBSPP 64
+#define ARRAYSPP 25
+#define SDOTSPP 64
+#define VALSPP 128
+#define BCDSPP 64
+
+
+#define HUNK2SPP 64             /* hunk page sizes */
+#define HUNK4SPP 32
+#define HUNK8SPP 16
+#define HUNK16SPP 8
+#define HUNK32SPP 4
+#define HUNK64SPP 2
+#define HUNK128SPP 1
+#define VECTORSPP 512
+
+/* offset of size info from beginning of vector,  in longwords */
+/* these values are not valid when a vector is stored in the free */
+/* list, in which case the chaining is done through the propery field */
+#define VSizeOff -2
+#define VPropOff -1
+
+/* VecTotSize: the total number of longwords for the data segment of
+ * the vector. Takes a byte count and rounds up to nearest long.
+ */
+
+#define VecTotSize(x)  (((x)+3) >> 2)
+#define VecTotToByte(x) ((x) * sizeof(long))
+
+/* these vector size macros determine the number of complete objects
+   in the vector
+ */
+#define VecSize(x)     ((x) >> 2)
+#define VecWordSize(x) ((x) >> 1)
+#define VecByteSize(x) (x)
+
+/* maximum and minimum fixnums */
+#define MaxINT 0x3fffffff
+#define MinINT (- 0x4000000)
+/* 
+ * macros for saving state and restoring state
+ *
+ * Savestack and Restorestack are required at the beginning and end of
+ * functions which modify the stack pointers np and lbot.
+ * The Savestack(n) should appear at the end of the variable declarations
+ * The n refers to the number of register variables declared in this routine.
+ * The information is required for the Vax version only.
+ */
+#ifdef PORTABLE
+extern struct atom nilatom, eofatom;
+#define nil    ((lispval) &nilatom)
+#define eofa   ((lispval) &eofatom)
+#define Savestack(n) struct argent *OLDlbot = lbot, *OLDnp = np
+#define Restorestack() (lbot = OLDlbot), np = OLDnp
+#else
+#define nil    ((lispval) 0)
+#define eofa   ((lispval) 20)
+#define Savestack(n) snpand(n)
+#define Restorestack() 
+#endif
+
+#define        CNIL    ((lispval) (OFFSET-4))
+#define NOTNIL(a)      (nil!=a)
+#define ISNIL(a)       (nil==a)
+
+#ifdef SPISFP
+extern long *xsp, xstack[];
+#define sp() xsp
+#define stack(z) (xsp > xstack ? (*--xsp = z): xserr())
+#define unstack() (*xsp++)
+#define Keepxs() long *oxsp = xsp;
+#define Freexs() xsp = oxsp;
+#else
+extern long *sp(), stack(), unstack();
+#define Keepxs() /* */
+#define Freexs() /* */
+#endif
+
+extern char typetable[];  /*  the table with types for each page  */
+#define ATOX(a1)       ((((int)(a1)) - OFFSET) >> 9)
+#define        TYPE(a1)        ((typetable+1)[ATOX(a1)])
+#define        TYPL(a1)        ((typetable+1)[ATOX(a1)])
+#define SETTYPE(a1,b,c)   {if((itemp = ATOX(a1)) >= fakettsize) \
+                        { if(fakettsize >= TTSIZE) \
+                          {\
+                             printf(" all space exausted, goodbye\n");\
+                             exit(1);\
+                          }\
+                          fakettsize++;  badmem(c);\
+                        }\
+                       (typetable + 1)[itemp] = (b); }
+
+#define        HUNKP(a1)       ((TYPE(a1) >= 11) & (TYPE(a1) <= 17))
+#define        HUNKSIZE(a1)    ((TYPE(a1)+5) & 15)
+
+#define VALID(a)       (a >= CNIL && a < datalim)
+
+#define Popframe() (errp->olderrp)
+
+
+/* some types ***********************************************************/
+#define lispint long
+#define MAX10LNG 200000000             /* max long divided by 10       */
+
+
+typedef union lispobj *lispval ;
+
+struct dtpr {
+       lispval cdr, car;
+};
+
+struct sdot {
+       int     I;
+       lispval CDR;
+};
+
+
+struct atom    {
+       lispval         clb;            /* current level binding*/
+       lispval         plist;          /* pointer to prop list */
+#ifndef WILD
+       lispval         fnbnd;          /* function binding     */
+#endif
+       struct  atom    *hshlnk;        /* hash link to next    */
+       char            *pname;         /* print name   */
+       };
+#ifdef WILD
+#define fnbnd clb
+#endif
+
+struct array {
+       lispval accfun,         /*  access function--may be anything  */
+               aux;            /*  slot for dimensions or auxilliary data  */
+       char *data;             /*  pointer to first byte of array    */
+       lispval length, delta;  /* length in items and length of one item */
+};
+
+struct bfun {
+       lispval (*start)();     /*  entry point to routine  */
+       lispval discipline,     /*  argument-passing discipline  */
+               language,       /*  language coded in   */
+               params,         /*  parameter list if relevant  */
+               loctab;         /*  local table  */
+};
+
+struct Hunk {
+       lispval hunk[1];
+};
+
+struct Vector {
+        lispval vector[1];
+};
+
+/* the vectori types */
+struct Vectorb {
+       char vectorb[1];
+};
+
+struct Vectorw {
+       short  vectorw[1];
+};
+
+struct Vectorl {
+    long vectorl[1];
+};
+
+union lispobj {
+       struct atom a;
+       FILE *p;
+       struct dtpr d;
+       long int i;
+       long int *j;
+       double r;
+       lispval (*f)();
+       struct array ar;
+       struct sdot s;
+       char c;
+       lispval l;
+       struct bfun bcd;
+       struct Hunk h;
+       struct Vector v;
+       struct Vectorb vb;
+       struct Vectorw vw;
+       struct Vectorl vl;
+};
+
+#ifdef lint
+extern lispval Inewint();
+#define inewint(p) Inewint((long)(p))
+#else
+extern lispval inewint();
+#endif
+
+
+#include "sigtab.h"   /* table of all pointers to lisp data */
+
+/* Port definitions *****************************************************/
+extern FILE    *piport,                /* standard input port          */
+       *poport,                /* standard output port         */
+       *errport,               /* port for error messages      */
+       *rdrport;               /* temporary port for readr     */
+extern FILE *xports[];         /* page of file *'s for lisp    */
+extern int lineleng ;          /* line length desired          */
+extern char rbktf;             /* logical flag: ] mode         */
+extern unsigned char *ctable;          /* Character table in current use */
+#define Xdqc ctable[131]
+#define Xesc ctable[130]
+#define Xsdc ctable[129]
+
+/* name stack ***********************************************************/
+
+#define NAMESIZE 3072
+
+/* the name stack limit is raised by NAMINC every namestack overflow to allow
+   a user function to handle the error
+*/
+#define NAMINC 25
+
+extern struct nament {
+       lispval val,
+               atm;
+}      *bnp,                   /* first free bind entry*/
+       *bnplim;                /* limit of bindstack   */
+
+struct argent {
+       lispval val;
+};
+extern struct argent *lbot, *np, *namptr;
+extern struct nament   *bnp;                   /* first free bind entry*/
+extern struct argent *nplim;           /* don't have this = np */
+extern struct argent *orgnp;   /* used by top level to reset to start  */
+extern struct nament *orgbnp;  /* used by top level to reset to start  */
+extern struct nament *bnplim;          /* limit of bindstack   */
+extern struct argent   *np,                    /* top entry on stack   */
+               *lbot,                  /* bottom of cur frame  */
+               *namptr;                /* temporary pointer    */
+extern lispval sigacts[16];
+extern lispval hunk_pages[7], hunk_items[7], hunk_name[7];
+
+extern lispval Vprintsym;
+
+#define TNP    if(np >= nplim) namerr();
+
+#define TNP    if(np >= nplim) namerr();
+#define INRNP  if (np++ >= nplim) namerr();
+#define protect(p) (np++->val = (p))
+#define chkarg(p,x); if((p)!=np-lbot) argerr(x);
+
+
+/** status codes **********************************************/
+/*                                                           */
+/* these define how status and sstatus should service probes  */
+/* into the lisp data base                                   */
+
+/* common status codes */
+#define ST_NO 0
+
+/* status codes */
+#define ST_READ 1
+#define ST_FEATR 2
+#define ST_SYNT 3
+#define ST_RINTB 4
+#define ST_NFETR 5
+#define ST_DMPR  6
+#define ST_CTIM  7
+#define ST_LOCT  8
+#define ST_ISTTY 9
+#define ST_UNDEF 10
+
+/* sstatus codes */
+#define ST_SET 1
+#define ST_FEATW 2
+#define ST_TOLC 3
+#define ST_CORE 4
+#define ST_INTB 5
+#define ST_NFETW 6
+#define ST_DMPW  7
+#define ST_AUTR 8
+#define ST_TRAN 9
+#define ST_BCDTR 10
+#define ST_GCSTR 11
+
+
+/* number of counters for fasl to use in a profiling lisp  */
+#define NMCOUNT 5000
+
+/* hashing things *******************************************************/
+#define        HASHTOP 1024    /*  we handle 8-bit characters by dropping top bit  */
+extern struct  atom    *hasht[HASHTOP];
+extern int     hash;           /* set by ratom         */
+extern int     atmlen;         /* length of atom including final null  */
+
+
+/** exception handling ***********************************************/
+extern int exception;  /* if TRUE then an exception is pending, one of */
+                       /* the below                                    */
+extern int sigintcnt;   /* if > 0 then there is a SIGINT pending       */
+
+/* big string buffer for whomever needs it ******************************/
+extern char    *strbuf;
+extern char    *endstrb;
+extern int     strbsize;
+
+/* break and error declarations *****************************************/
+#define        SAVSIZE 44              /* number of bytes saved by setexit     */
+#define        BRRETB  1
+#define BRCONT 2
+#define        BRGOTO  3
+#define        BRRETN  4
+#define INTERRUPT 5
+#define THROW  6
+extern int     depth;          /* depth of nested breaks               */
+extern lispval contval;        /* the value being returned up          */
+extern int     retval;         /* used by each error/prog call         */
+extern lispval  lispretval;    /* used by non-local go                 */
+extern int     rsetsw;         /* used by *rset mode                   */
+extern int     evalhcallsw;    /* used by evalhook                     */
+extern int     funhcallsw;     /* used by evalhook                     */
+
+
+/* other stuff **********************************************************/
+extern lispval ftemp,vtemp,argptr,ttemp;       /* temporaries: use briefly  */
+extern int itemp;
+                                       /* for pointer type conversion  */
+#include       "dfuncs.h"
+
+#define        NUMBERP 2
+#define        BCDP    5
+#define        PORTP   6
+#define ARRAYP 7
+
+#define        ABSVAL  0
+#define        MINUS   1
+#define        ADD1    2
+#define        SUB1    3
+#define        NOT     4
+#define        LNILL   5
+#define        ZEROP   6
+#define        ONEP    7
+#define        PLUS    8
+#define        TIMES   9
+#define        DIFFERENCE      10
+#define        QUOTIENT        11
+#define        MOD     12
+#define        LESSP   13
+#define        GREATERP        14
+#define        SUM     15
+#define        PRODUCT 16
+#define        AND     17
+#define        OR      18
+#define        XOR     19
+
+interpt();
+handler();  extern sigdelay, sigstruck;
+
+/* limit of valid data area **************************************/
+
+extern lispval datalim;
+
+/** macros to push and pop the value of an atom on the stack ******/
+
+#define PUSHDOWN(atom,value)\
+       {bnp->atm=(atom);bnp++->val=(atom)->a.clb;(atom)->a.clb=value;\
+       if(bnp>bnplim) binderr();}
+
+#define POP\
+       {--bnp;bnp->atm->a.clb=bnp->val;}
+
+/* PUSHVAL  is used to store a specific atom and value on the
+ * bindstack.   Currently only used by closure code
+ */  
+#define PUSHVAL(atom,value)\
+       {bnp->atm=(atom);bnp++->val=value;\
+       if(bnp>bnplim) binderr();}
+
+/** macro for evaluating atoms in eval and interpreter  ***********/
+
+#define EVALATOM(x)    vtemp = x->a.clb;\
+                       if( vtemp == CNIL ) {\
+                               printf("%s: ",(x)->a.pname);\
+                               vtemp = error("UNBOUND VARIABLE",TRUE);}
+
+/*  having to do with small integers                                   */
+extern long Fixzero[];
+#define SMALL(i)       ((lispval)(Fixzero + i))
+#define P(p)           ((lispval) (xports +((p)-_iob)))
+#define PN(p)          ((int) ((p)-_iob))
+#define okport(arg,default) (vtemp = arg,((TYPE((vtemp))!=PORT)?default:(vtemp)->p))
+
+extern lispval ioname[];       /* names of open files */
+/*  interpreter globals   */
+
+extern int lctrace;
+
+/* register lisp macros for registers */
+
+#define saveonly(n)    asm("#save      n")
+#define snpand(n)      asm("#protect   n")
diff --git a/usr/src/ucb/lisp/franz/inits.c b/usr/src/ucb/lisp/franz/inits.c
new file mode 100644 (file)
index 0000000..3868a7d
--- /dev/null
@@ -0,0 +1,215 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: inits.c,v 1.5 83/09/12 14:17:34 sklower Exp $";
+#endif
+
+/*                                     -[Sat Jan 29 12:59:39 1983 by jkf]-
+ *     inits.c                         $Locker:  $
+ * initialization routines
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+
+#include "global.h"
+#include <signal.h>
+#include "frame.h"
+
+/* initial
+ * initializes the parts of the system that cannot be automatically
+ * accomplished in the declarations.
+ */
+int reborn=0;  /*  flag to tell whether we are in fast-load version  */
+extern char *stabf;
+extern int fvirgin;
+extern int keywait;
+extern sigstruck, sigdelay;
+initial()
+{
+       int sigalrmh(), sigfpeh(),  siginth();
+       lispval Isstatus(),Istsrch();
+       extern int hashtop;
+
+       /* clear any memory of pending SIGINT's */
+       exception = FALSE;
+       sigintcnt = 0;
+
+       if( signal(SIGINT,SIG_IGN) != SIG_IGN)
+             signal(SIGINT,siginth);
+       if( signal(SIGHUP,SIG_IGN) != SIG_IGN)
+             signal(SIGHUP,siginth);
+       signal(SIGFPE,siginth);
+       signal(SIGALRM,siginth);
+       signal(SIGPIPE,siginth);
+       /* signals SIGBUS and SIGSEGV will be set up when the status list
+          is set up when the lisp is virgin, and will be set up according
+          to the current value on the status list if the lisp is reborn
+       */
+
+#ifdef SPISFP
+       {extern long *exsp; xsp = exsp;}
+#endif
+
+       if( reborn ) {
+               register FILE *p = _iob + 3;
+               static FILE empty;
+               for(; p < _iob + _NFILE; p++)
+                       *p = empty;
+               np = lbot = orgnp;
+               stabf = 0;
+               fvirgin = 1;
+               loading->a.clb = nil;
+               gcrebear();
+
+               /* set up SIGBUS and SIGSEGV from current value 
+                  of status flag dumpcore
+               */
+               Isstatus(matom("dumpcore"),
+                        (Istsrch(matom("dumpcore")))->d.cdr->d.cdr->d.cdr);
+
+               makenv();
+               return;
+       }
+       for (hash=0;hash<hashtop;hash++) hasht[hash] = (struct atom *) CNIL;
+       
+       sbrk( LBPG-(((int)sbrk(0)) % LBPG) );   /* even up the break */
+       makevals();
+
+       orgnp = np;
+       makenv();
+
+}
+
+static
+makenv()
+{
+       register lispval env, temp;
+       register char *p, *q;
+       char **envp, envstr[STRBLEN];
+       extern char **environ;
+
+       lbot = np;
+       env = nil;
+       np++->val = env;
+       for (envp=environ; *envp!=NULL; envp++) ;
+       while (--envp >= environ) {
+               for(p= *envp,q=envstr; *p!='=' ; p++)
+                       if(q < envstr + STRBLEN)
+                               *q++ = *p;
+               *q = 0; p++;
+               /* at this point lbot->val==env, so it is protected
+                  from gc */
+               lbot->val = temp = newdot();
+               temp->d.cdr = env;
+               env = temp;
+               temp = newdot();
+               env->d.car = temp;
+               temp->d.car = matom(envstr);
+               temp->d.cdr = matom(p);
+       }
+       matom("environment")->a.clb = env;
+       np--;
+}
+
+siginth(signo){
+       re_enable(signo,siginth);
+       sigstruck |= (1 << signo);
+       /* handle SIGINT differently since it is the only
+          asychronous interrupt we handle              */
+       if( signo == SIGINT) {
+           if( ++sigintcnt == 1)
+           {  /* if this is the first interrupt, we just set a flag
+                 which will be checked in qfuncl and eval.  This will
+                 allow us to handle these interrupts when we are
+                 ready.
+              */
+              exception = TRUE;
+              /*putchar('A');*/
+              fflush(stdout);
+              sigstruck &= ~(1 << signo);
+              return;
+           }
+           else if (sigintcnt == 2)
+           {  /* the setting of  exception was ignored, we better
+                 make sure that all calls from compiled code
+                 go through qlinker
+               */
+               signal(SIGINT,SIG_IGN);  /* this may take a while, dont allow ints*/
+               clrtt(0);
+               /*putchar('B');*/
+               fflush(stdout);
+               signal(SIGINT,siginth);  /* ok to interrupt again */
+               sigstruck &= ~(1 << signo);
+               return;
+           }
+           else {
+               /*putchar('C');*/
+               fflush(stdout);
+           }
+       }
+
+       sigcall(signo);
+}
+sigcall(which)
+register which;
+{
+       extern lispval Lfuncal();
+       Savestack(1);
+
+       if(which == SIGINT) { sigintcnt = 0; exception = 0; }
+
+       if(sigacts[which]!=((lispval) 0)) {
+               pbuf pb;
+               int mustpop = 0;
+               if(errp && errp->class==F_TO_FORT) {
+                       np = errp->svnp;
+                       mustpop = 1;
+                       errp = Pushframe(F_TO_LISP,nil,nil);
+               }
+               lbot = np;
+               np -> val = sigacts[which];
+               INRNP;
+               np -> val = inewint((long)which);
+               INRNP;
+       {lispval temp;temp = rdrsdot, rdrsdot = rdrsdot2, rdrsdot2 = temp; /*KLUDGE*/}
+               Lfuncal();
+               if (mustpop) errp = Popframe();
+       {lispval temp;temp = rdrsdot, rdrsdot = rdrsdot2, rdrsdot2 = temp; /*KLUDGE*/}
+       }
+       sigstruck &= ~ (1<<which);
+       Restorestack();
+}
+delayoff(){
+       sigdelay = FALSE;
+       if(sigstruck)
+               dosig();
+}
+dosig()
+{
+       register int i; int which;
+       if(!sigdelay) 
+               for(which=0, i = 1;  i <= 65536;  which++,i<<=1) {
+                       keywait = FALSE;
+                       if(sigstruck & i)
+                               sigcall(which);
+               }
+}
+badmemr(number)
+{
+       signal(number,badmemr);
+       fflush(stdout);
+       error("Internal bad memory reference, you are advised to (reset).",FALSE);
+}
+
+#define        mask(s) (1 << ((s)-1))
+static
+re_enable(signo,handler)
+int (*handler)();
+{
+#if os_4_2
+       sigsetmask(sigblock(0) &~ mask(signo));
+#else
+       signal(signo,handler);
+#endif
+}
diff --git a/usr/src/ucb/lisp/franz/io.c b/usr/src/ucb/lisp/franz/io.c
new file mode 100644 (file)
index 0000000..63fc5a2
--- /dev/null
@@ -0,0 +1,1020 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: /na/franz/franz/RCS/io.c,v 1.8 83/08/06 08:38:42 jkf Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:45:22 1983 by jkf]-
+ *     io.c                            $Locker:  $
+ * input output functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include <ctype.h>
+#include "chars.h"
+#include "chkrtab.h"
+
+struct readtable {
+unsigned char  ctable[132];
+} initread = {
+/*     ^@ nul  ^A soh  ^B stx  ^C etx  ^D eot  ^E eng  ^F ack  ^G bel  */
+       VERR,   VERR,   VERR,   VERR,   VERR,   VERR,   VERR,   VERR,
+/*     ^H bs   ^I ht   ^J nl   ^K vt   ^L np   ^M cr   ^N so   ^O si   */
+       VCHAR,  VSEP,   VSEP,   VSEP,   VSEP,   VSEP,   VERR,   VERR,
+/*     ^P dle  ^Q dc1  ^R dc2  ^S dc3  ^T dc4  ^U nak  ^V syn  ^W etb  */
+       VERR,   VERR,   VERR,   VERR,   VERR,   VERR,   VERR,   VERR,
+/*     ^X can  ^Y em   ^Z sub  ^[ esc  ^\ fs   ^] gs   ^^ rs   ^_ us   */
+       VERR,   VERR,   VERR,   VSEP,   VERR,   VERR,   VERR,   VERR,
+/*     sp      !       "       #       $       %       &       '       */
+       VSEP,   VCHAR,  VSD,    VCHAR,  VCHAR,  VCHAR,  VCHAR,  VSQ,
+/*     (       )       *       +       ,       -       .       /       */
+       VLPARA, VRPARA, VCHAR,  VSIGN,  VCHAR,  VSIGN,  VPERD,  VCHAR,
+/*     0       1       2       3       4       5       6       7       */
+       VNUM,   VNUM,   VNUM,   VNUM,   VNUM,   VNUM,   VNUM,   VNUM,
+/*     8       9       :       ;       <       =       >       ?       */
+       VNUM,   VNUM,   VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,
+/*     @       A       B       C       D       E       F       G       */
+       VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,
+/*     H       I       J       K       L       M       N       O       */
+       VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,
+/*     P       Q       R       S       T       U       V       W       */
+       VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,
+/*     X       Y       Z       [       \       ]       ^       _       */
+       VCHAR,  VCHAR,  VCHAR,  VLBRCK, VESC,   VRBRCK, VCHAR,  VCHAR,
+/*     `       a       b       c       d       e       f       g       */
+       VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,
+/*     h       i       j       k       l       m       n       o       */
+       VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,
+/*     p       q       r       s       t       u       v       w       */
+       VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,  VCHAR,
+/*     x       y       z       {       |       }       ~       del     */
+       VCHAR,  VCHAR,  VCHAR,  VCHAR,  VDQ,    VCHAR,  VCHAR,  VERR,
+/*     unused  Xsdc    Xesc    Xdqc                                    */
+       0,      '"',    '\\',   '|'
+};
+
+extern unsigned char *ctable;
+lispval atomval;       /* external varaible containing atom returned
+                          from internal atom reading routine */
+lispval readrx(); lispval readr(); lispval readry();
+char *atomtoolong();
+int keywait;
+int plevel = -1;       /* contains maximum list recursion count        */
+int plength = -1;   /* maximum number of list elements printed */
+static int dbqflag;
+static int mantisfl = 0;
+extern int uctolc;
+extern lispval lastrtab;       /* external variable designating current reader
+                          table */
+static char baddot1[]=
+"Bad reader construction: (. <something>)\nShould be (nil . <something>)\n";
+static char baddot2[]=
+"Bad reader construction: (<something> .)\n\
+Should be (<something> . <something>), assumed to be (<something>)";
+static char baddot3[]=
+"Bad reader construction: (<something> . <something> not followed by )";
+
+/* readr ****************************************************************/
+/* returns a s-expression read in from the port specified as the first */
+/* argument.  Handles superbrackets, reader macros.                    */
+lispval
+readr(useport)
+FILE *useport;
+{
+       register lispval handy = Vreadtable->a.clb;
+
+       chkrtab(handy);
+       rbktf = FALSE;
+       rdrport = (FILE *) useport;
+       if(useport==stdin)
+               keywait = TRUE; 
+       handy = readrx(Iratom());
+       if(useport==stdin)
+               keywait = FALSE;
+       return(handy);
+
+}
+
+
+/* readrx **************************************************************/
+/* returns a s-expression beginning with the syntax code of an atom    */
+/* passed in the first */
+/* argument.  Does the actual work for readr, including list, dotted   */
+/* pair, and quoted atom detection                                     */
+lispval
+readrx(code)
+register int code;
+{
+       register lispval work;
+       register lispval *current;
+       register struct argent *result;
+       int inlbkt = FALSE;
+       lispval errorh();
+       Savestack(4); /* ???not necessary because np explicitly restored if
+         changed */
+
+top:
+       switch(code)
+       {
+       case TLBKT:
+               inlbkt = TRUE;
+       case TLPARA:
+               result = np;
+               current = (lispval *)np;
+               np++->val = nil; /*protect(nil);*/
+               for(EVER) {
+                       switch(code = Iratom())
+                       {
+                       case TRPARA:
+                               if(rbktf && inlbkt)
+                                       rbktf = FALSE;
+                               goto out;
+                       default:
+                               atomval = readrx(code);
+                       case TSCA:
+                               np++->val=atomval;
+                               *current = work = newdot();
+                               work->d.car = atomval;
+                               np--;
+                               current = (lispval *) &(work->d.cdr);
+                               break;
+                       case TINF:
+                               imacrox(result->val,TRUE);
+                               work = atomval;
+                               result->val = work->d.car;
+                               current = (lispval *) & (result->val);
+                               goto mcom;
+                       case TSPL:
+                               macrox(); /* input and output in atomval */
+                               *current = atomval;
+                       mcom:
+                               while(*current!=nil) {
+                                       if(TYPE(*current)!=DTPR)
+                                               errorh1(Vermisc,"Non-list returned from splicing macro",nil,FALSE,7,*current);
+                                       current=(lispval *)&((*current)->d.cdr);
+                               }
+                               break;
+                       case TPERD:
+                               if(result->val==nil) {
+                                       work = result->val=newdot();
+                                       current = (lispval *) &(work->d.cdr);
+                                       fprintf(stderr,baddot1);
+                               }
+                               code = Iratom();
+                               if(code==TRPARA) {
+                                       result->val = errorh1(Vermisc,baddot2,nil,TRUE,58,result->val);
+                                       goto out;
+                               }
+                               *current = readrx(code);
+                               /* there is the possibility that the expression
+                                  following the dot is terminated with a "]"
+                                  and thus needs no closing lparens to follow
+                               */
+                               if(!rbktf && ((code = Iratom()))!=TRPARA) {
+                                       errorh2(Vermisc,baddot3,nil,TRUE,59,result->val,atomval);
+                               }
+                               if(rbktf && inlbkt)
+                                       rbktf = FALSE;
+                               goto out;
+                       case TEOF:
+                               errorh1(Vermisc,"Premature end of file after ", 
+                                                         nil,FALSE,0,result->val);
+                       }
+                       if(rbktf) {
+                               if(inlbkt)
+                                       rbktf = FALSE;
+                               goto out;
+                       }
+               }
+       case TSCA:
+               Restorestack();
+               return(atomval);
+       case TEOF:
+               Restorestack();
+               return(eofa);
+       case TMAC:
+               macrox();
+               Restorestack();
+               return(atomval);
+       case TINF:
+               imacrox(nil,FALSE);
+               work = atomval;
+               if(work==nil) { code = Iratom(); goto top;}
+               work = work->d.car;
+               Restorestack();
+               if(work->d.cdr==nil)
+                   return(work->d.car);
+               else
+                   return(work);
+       case TSPL:
+               macrox();
+               if((work = atomval)!=nil) {
+                       if(TYPE(work)==DTPR && work->d.cdr==nil) {
+                               Restorestack();
+                               return(work->d.car);
+                       } else {
+                               errorh1(Vermisc,
+"Improper value returned from splicing macro at top-level",nil,FALSE,9,work);
+                       }
+               }
+               code = Iratom();
+               goto top;
+               /* return(readrx(Iratom())); */
+       case TSQ:
+               result = np;
+               protect(newdot());
+               (work = result->val)->d.car = quota;
+               work = work->d.cdr = newdot();
+               work->d.car = readrx(Iratom());
+               goto out;
+
+       case TRPARA:
+               Restorestack();
+               return(errorh(Vermisc,
+                   "read: read a right paren when expecting an s-expression",
+                   nil,FALSE,0));
+       case TPERD:
+               Restorestack();
+               return(errorh(Vermisc,
+                   "read: read a period when expecting an s-expression",
+                   nil,FALSE,0));
+                   
+       /* should never get here, we should have covered all cases above */
+       default:
+               Restorestack();
+               return(errorh1(Vermisc,"Readlist error,  code ",nil,FALSE,0,inewint((long)code)));
+       }
+out:
+       work = result->val;
+       np = result;
+       Restorestack();
+       return(work);
+}
+macrox()
+{
+       FILE *svport;
+       lispval handy, Lapply();
+
+       Savestack(0);
+       svport = rdrport;       /* save from possible changing */
+       lbot = np;
+       protect(handy=Iget(atomval,lastrtab));
+       if (handy == nil)
+       {
+           errorh1(Vermisc,"read: can't find the character macro for ",nil,
+                       FALSE,0,atomval);
+       }
+       protect(nil);
+       atomval = Lapply();
+       chkrtab(Vreadtable->a.clb);     /* the macro could have changed
+                                          the readtable
+                                        */
+       rdrport = svport;       /* restore old value */
+       Restorestack();
+       return;
+}
+imacrox(current,inlist)
+register lispval current;
+{
+       FILE *svport;
+       register lispval work;
+       lispval Lapply(), handy;
+
+       Savestack(2);
+       svport = rdrport;       /* save from possible changing */
+       if(inlist)
+       {
+           protect(handy = newdot());
+           handy->d.car = current;
+           for(work = handy->d.car; (TYPE(work->d.cdr))==DTPR; )
+               work = work->d.cdr;
+            handy->d.cdr = work;
+       }
+       else handy = current;
+       
+       lbot = np;
+       protect(Iget(atomval,lastrtab));
+       protect(handy);
+       atomval = Lfuncal();
+       chkrtab(Vreadtable->a.clb);     /* the macro could have changed
+                                          the readtable
+                                        */
+       rdrport = svport;       /* restore old value */
+       Restorestack();
+       return;
+}
+
+
+
+/* ratomr ***************************************************************/
+/* this routine returns a pointer to an atom read in from the port given*/
+/* by the first argument                                               */
+lispval
+ratomr(useport)
+register FILE  *useport;
+{
+       rdrport = useport;
+       switch(Iratom())
+       {
+       case TEOF:
+               return(eofa);
+       case TSQ:
+       case TRPARA:
+       case TLPARA:
+       case TLBKT:
+       case TPERD:
+               strbuf[1]=0;
+               return(getatom(TRUE));
+       default:
+               return(atomval);
+       }
+}
+
+#define push(); *name++ = c; if(name>=endstrb) name = atomtoolong(name);
+#define next() (((cc=getc(useport))!=EOF)?(stats = ctable[c = cc &0177]):\
+                                       ((c=0),(saweof = 1),(stats = SEPMASK)))
+Iratom()
+{
+       register FILE   *useport = rdrport;
+       register char   c, marker, *name;
+       extern lispval finatom(), calcnum(), getnum();
+       int code, cc;
+       int strflag = FALSE;
+
+       name = strbuf;
+
+again: cc = getc(useport);
+       if(cc==EOF)
+       {
+           clearerr(useport);
+           return(TEOF);
+       }
+       c = cc & 0177;
+       *name = c;
+
+       switch(synclass(ctable[c])) {
+
+       default:        goto again;
+
+       case synclass(VNUM):
+
+       case synclass(VSIGN):   *name++ = c;
+                       atomval = (getnum(name));
+                       return(TSCA);
+
+       case synclass(VESC):
+                       dbqflag = TRUE;
+                       *name++ = getc(useport) & 0177;
+                       atomval = (finatom(name));
+                       return(TSCA);
+                       
+       case synclass(VCHAR):
+                       if(uctolc && isupper(c)) c = tolower(c);
+                       *name++ = c;
+                       atomval = (finatom(name));
+                       return(TSCA);
+
+       case synclass(VLPARA):  return(TLPARA);
+
+       case synclass(VRPARA):  return(TRPARA);
+
+       case synclass(VPERD):   marker = peekc(useport) & 0177;
+                       if(synclass(VNUM)!=synclass(ctable[marker]))
+                       {  if(SEPMASK & ctable[marker])
+                               return(TPERD);
+                          else { *name++ = c;  /* this period begins an atm */
+                                 atomval = finatom(name);
+                                 return(TSCA);
+                          }
+                       }
+                       *name++ = '.';
+                       mantisfl = 1;
+                       atomval = (getnum(name));
+                       return(TSCA);
+
+       case synclass(VLBRCK):  return(TLBKT);
+
+       case synclass(VRBRCK):  rbktf = TRUE;
+                       return(TRPARA);
+
+       case synclass(VSQ):     return(TSQ);
+
+       case synclass(VSD):     strflag = TRUE;
+       case synclass(VDQ):     name = strbuf;
+                       marker = c;
+                       while ((c = getc(useport)) != marker) {
+
+                               if(synclass(VESC)==synclass(ctable[c]))
+                                       c = getc(useport) & 0177;
+                               push();
+                               if (feof(useport)) {
+                                       clearerr(useport);
+                                       error("EOF encountered while reading atom", FALSE);
+                               }
+                       }
+                       *name = NULL_CHAR;
+                       if(strflag)
+                               atomval = (lispval) pinewstr(strbuf);
+                       else
+                               atomval = (getatom(TRUE));
+                       return(TSCA);
+
+       case synclass(VERR):    if (c == '\0') 
+                       {
+                         fprintf(stderr,"[read: null read and ignored]\n");
+                         goto again;   /* null pname */
+                       }
+                       fprintf(stderr,"%c (%o): ",c,(int) c);
+                       error("ILLEGAL CHARACTER IN ATOM",TRUE);
+
+       case synclass(VSINF):
+               code = TINF;
+               goto same;
+       case synclass(VSSPL):
+               code = TSPL;
+               goto same;
+       case synclass(VSMAC):
+               code = TMAC;
+       same:
+               marker = peekc(rdrport);
+               if(! (SEPMASK & ctable[marker]) ) {
+                   *name++ = c;  /* this is not a macro */
+                   atomval = (finatom(name));
+                   return(TSCA);
+               }
+               goto simple;
+       case synclass(VINF):
+               code = TINF;
+               goto simple;
+       case synclass(VSCA):
+               code = TSCA;
+               goto simple;
+       case synclass(VSPL):
+               code = TSPL;
+               goto simple;
+       case synclass(VMAC):
+               code = TMAC;
+       simple:
+               strbuf[0] = c;
+               strbuf[1] = 0;
+               atomval = (getatom(TRUE));
+               return(code);
+       }
+}
+
+lispval
+getnum(name)
+register char *name;
+{
+       unsigned char c;
+       register lispval result;
+       register FILE *useport=rdrport;
+       unsigned char  stats;
+       int sawdigit = 0, saweof = 0,cc;
+       char *exploc = (char *) 0;
+       double realno;
+       extern lispval finatom(), calcnum(), newdoub(), dopow();
+
+       if(mantisfl) {
+               mantisfl = 0;
+               next();
+               goto mantissa;
+       }
+       if(VNUM==ctable[*(unsigned char*)(name-1)]) sawdigit = 1;
+       while(VNUM==next()) {
+               push();         /* recognize [0-9]*, in "ex" parlance */
+               sawdigit = 1;
+       }
+       if(c=='.') {
+               push();         /* continue */ 
+       } else if(stats & SEPMASK) {
+               if(!saweof)ungetc((int)c,useport);
+               return(calcnum(strbuf,name,(int)ibase->a.clb->i));
+       } else if(c=='^') {
+               push();
+               return(dopow(name,(int)ibase->a.clb->i));
+       } else if(c=='_') {
+               if(sawdigit)    /* _ must be preceeded by a digit */
+               {
+                   push();
+                   return(dopow(name,2));
+               }
+               else goto backout;
+       } else if(c=='e' || c=='E' || c=='d' ||c=='D') {
+               if(sawdigit) goto expt;
+               else goto backout;
+       } else {
+       backout:
+               ungetc((int)c,useport);
+               return(finatom(name));
+       }
+                               /* at this point we have [0-9]*\. , which might
+                                  be a decimal int or the leading part of a
+                                  float                                */
+       if(next()!=VNUM) {
+               if(c=='e' || c=='E' || c=='d' ||c=='D')
+                       goto expt;
+               else if(c=='^') {
+                       push();
+                       return(dopow(name,(int)ibase->a.clb->i));
+               } else if(c=='_') {
+                       push();
+                       return(dopow(name,2));
+               } else if( stats & SEPMASK) {
+                               /* Here we have 1.x where x is not number
+                                * but is a separator 
+                                * Here we have decimal int. NOT FORTRAN!
+                                */
+                       if(!saweof)ungetc((int)c,useport);
+                       return(calcnum(strbuf,name-1,10));
+               }
+               else goto last;  /* return a symbol */
+       }
+mantissa:
+       do {
+               push();
+       } while (VNUM==next());
+       
+       /* Here we have [0-9]*\.[0-9]*
+        * three possibilities:
+        *   next character is e,E,d or D in which case we examine
+        *      the exponent [then we are faced with a similar
+        *      situation to this one: is the character after the
+        *      exponent a separator or not]
+        *   next character is a separator, in which case we have a
+        *      number (without an exponent)
+        *   next character is not a separator in which case we have
+        *      an atom (whose prefix just happens to look like a
+        *      number)
+        */
+       if( (c == 'e') || (c == 'E') || (c == 'd') || (c == 'D')) goto expt;
+       
+       if(stats & SEPMASK) goto verylast;      /* a real number */
+       else goto last; /* prefix makes it look like a number, but it isn't */
+       
+expt:
+       exploc = name;  /* remember location of exponent character */
+       push();
+       next();
+       if(c=='+' || c =='-') {
+               push();
+               next();
+       }
+       while (VNUM==stats) {
+               push();
+               next();
+       }
+
+       /* if a separator follows then we have a number, else just
+        * an atom
+        */
+       if (stats & SEPMASK) goto verylast;
+       
+last:  /* get here when what looks like a number turns out to be an atom */
+       if(!saweof) ungetc((int)c,useport);
+       return(finatom(name));
+
+verylast:
+       if(!saweof) ungetc((int)c,useport);
+       /* scanf requires that the exponent be 'e' */
+       if(exploc != (char *) 0 ) *exploc = 'e';
+       *name=0;
+       sscanf(strbuf,"%F",&realno);
+       (result = newdoub())->r = realno;
+       return(result);
+}
+
+lispval
+dopow(part2,base)
+register char *part2;
+{
+       register char *name = part2;
+       register FILE *useport = rdrport;
+       register int power;
+       lispval work;
+       unsigned char stats,c;
+       int cc, saweof = 0;
+       char *end1 = part2 - 1; lispval Ltimes();
+       Savestack(4);
+
+       while(VNUM==next()) {
+               push();
+       }
+       if(c!='.') {
+               if(!saweof)ungetc((int)c,useport);
+       }
+       if(c!='.' && !(stats & SEPMASK)) {
+               return(finatom(name));
+       }
+       lbot = np;
+       np++->val = inewint(base);
+       /* calculate "mantissa"*/
+       if(*end1=='.')
+               np++->val = calcnum(strbuf,end1-1,10);
+       else
+               np++->val = calcnum(strbuf,end1,(int)ibase->a.clb->i);
+
+       /* calculate exponent */
+       if(c=='.')
+               power = calcnum(part2,name,10)->i;
+       else
+               power = calcnum(part2,name,(int)ibase->a.clb->i)->i;
+       while(power-- > 0)
+               lbot[1].val = Ltimes();
+       work = lbot[1].val;
+       Restorestack();
+       return(work);
+}
+       
+
+lispval
+calcnum(strbuf,name,base)
+register char *name;
+char *strbuf;
+{
+       register char *p;
+       register lispval result, temp;
+       int negflag = 0;
+
+       result = temp = newsdot();              /* initialize sdot cell */
+       protect(temp);
+       p = strbuf;
+       if(*p=='+') p++;
+       else if(*p=='-') {negflag = 1; p++;}
+       *name = 0;
+       if(p>=name) return(getatom(TRUE));
+
+       for(;p < name; p++)
+               dmlad(temp,(long)base,(long)*p-'0');
+       if(negflag)
+               dmlad(temp,-1L,0L);
+
+       if(temp->s.CDR==0) {
+               result = inewint(temp->i);
+               pruneb(np[-1].val);
+       }
+       np--;
+       return(result);
+}
+lispval
+finatom(name)
+register char *name;
+{
+       register FILE *useport = rdrport;
+       unsigned char c, stats;
+       int cc, saweof = 0;
+
+       while(!(next()&SEPMASK)) {
+
+               if(synclass(stats) == synclass(VESC)) {
+                       c = getc(useport) & 0177;
+               } else {
+                       if(uctolc && isupper(c)) c = tolower(c);
+               }
+               push();
+       }
+       *name = NULL_CHAR;
+       if(!saweof)ungetc((int)c,useport);
+       return(getatom(TRUE));
+}
+
+char *
+atomtoolong(copyto)
+char *copyto;
+{
+    int size;
+    register char *oldp = strbuf;
+    register char *newp;
+    lispval nveci();
+    /*
+     * the string buffer contains an string which is too long 
+     * so we get a bigger buffer.
+     */
+
+    size =  (endstrb - strbuf)*4 + 28 ;
+    newp = (char *) nveci(size);
+    atom_buffer = (lispval) newp;
+    strbuf = newp;
+    endstrb = newp + size - 1;
+    while(oldp < copyto) *newp++ = *oldp++;
+       return(newp);
+}
+    
+/* printr ***************************************************************/
+/* prints the first argument onto the port specified by the second     */
+
+/*
+ * Last modified Mar 21, 1980 for hunks
+ */
+
+printr(a,useport)
+register lispval a;
+register FILE *useport;
+{
+       register hsize, i;
+       char strflag = 0;
+       char Idqc = 0;
+       char *chstr;
+       int curplength = plength;
+       int quot;
+       lispval Istsrch();
+       lispval debugmode;
+
+val_loop:
+       if(! VALID(a)) {
+           debugmode = Istsrch(matom("debugging"))->d.cdr->d.cdr->d.cdr;
+           if(debugmode != nil) {
+               printf("<printr:bad lisp data: 0x%x>\n",a);
+               error("Bad lisp data encountered by printr", FALSE); 
+           } else {
+               a = badst;
+               printf("<printr:bad lisp data: 0x%x>",a);
+               return;
+           }
+       }
+
+       switch (TYPE(a))
+       {
+
+
+       case UNBO:      fputs("<UNBOUND>",useport);
+                       break;
+
+       case VALUE:     fputs("(ptr to)",useport);
+                       a = a->l;
+                       goto val_loop;
+
+       case INT:       fprintf(useport,"%d",a->i);
+                       break;
+
+       case DOUB:      {  char buf[64];
+                          lfltpr(buf,a->r);
+                          fputs(buf,useport);
+                       }
+                       break;
+
+       case PORT:      { lispval  cp;
+                         if((cp = ioname[PN(a->p)]) == nil)
+                            fputs("%$unopenedport",useport);
+                         else fprintf(useport,"%%%s",cp);
+                       }
+                       break;
+
+       case HUNK2:
+       case HUNK4:
+       case HUNK8:
+       case HUNK16:
+       case HUNK32:
+       case HUNK64:
+       case HUNK128:
+                       if(plevel == 0) 
+                       {   
+                            fputs("%",useport);
+                            break;
+                       }
+                       hsize = 2 << HUNKSIZE(a);
+                       fputs("{", useport);
+                       plevel--;
+                       printr(a->h.hunk[0], useport);
+                       curplength--;
+                       for (i=1; i < hsize; i++)
+                       {
+                           if (a->h.hunk[i] == hunkfree)
+                               break;
+                           if (curplength-- == 0)
+                           {
+                               fputs(" ...",useport); 
+                               break;
+                           }
+                           else
+                           {
+                               fputs(" ", useport);
+                               printr(a->h.hunk[i], useport);
+                           }
+                       }
+                       fputs("}", useport);
+                       plevel++;
+                       break;
+                       
+       case VECTOR:
+                       chstr = "vector";
+                       quot = 4;       /* print out # of longwords */
+                       goto veccommon;
+
+       case VECTORI:
+                       chstr = "vectori";
+                       quot = 1;
+          veccommon:
+                       /* print out 'vector' or 'vectori' except in
+                        * these circumstances:
+                        * property is a symbol, in which case print
+                        *  the symbol's pname
+                        * property is a list with a 'print' property,
+                        *  in which case it is funcalled to print the
+                        *  vector
+                        */
+                       if(a->v.vector[VPropOff] != nil)
+                       {
+                           if ((i=TYPE(a->v.vector[VPropOff])) == ATOM)
+                           {
+                               chstr = a->v.vector[VPropOff]->a.pname;
+                           }
+                           else if ((i == DTPR) && vectorpr(a,useport))
+                           {
+                               break;  /* printed by vectorpr */
+                           }
+                           else if ((i == DTPR)
+                                    && (a->v.vector[VPropOff]->d.car != nil)
+                                    && TYPE(a->v.vector[VPropOff]->d.car)
+                                        == ATOM)
+                           {
+                               chstr = a->v.vector[VPropOff]->d.car->a.pname;
+                           }
+                       }
+                       fprintf(useport,"%s[%d]",
+                                   chstr, a->vl.vectorl[VSizeOff]/quot);
+                       break;
+
+       case ARRAY:     fputs("array[",useport);
+                       printr(a->ar.length,useport);
+                       fputs("]",useport);
+                       break;
+
+       case BCD:       fprintf(useport,"#%X-",a->bcd.start);
+                       printr(a->bcd.discipline,useport);
+                       break;
+
+       case OTHER:     fprintf(useport,"#Other-%X",a);
+                       break;
+
+       case SDOT:      pbignum(a,useport);
+                       break;
+
+       case DTPR:      if(plevel==0)
+                       {
+                            fputs("&",useport);
+                            break;
+                       }
+                       plevel--;
+                       if(a->d.car==quota && a->d.cdr!=nil 
+                           && a->d.cdr->d.cdr==nil) {
+                               putc('\'',useport);
+                               printr(a->d.cdr->d.car,useport);
+                               plevel++;
+                               break;
+                       }
+                       putc('(',useport);
+                       curplength--;
+       morelist:       printr(a->d.car,useport);
+                       if ((a = a->d.cdr) != nil)
+                               {
+                               if(curplength-- == 0)
+                               {
+                                   fputs(" ...",useport);
+                                   goto out;
+                               }
+                               putc(' ',useport);
+                               if (TYPE(a) == DTPR) goto morelist;
+                               fputs(". ",useport);
+                               printr(a,useport);
+                               }
+               out:
+                       fputc(')',useport);
+                       plevel++;
+                       break;
+
+       case STRNG:     strflag = TRUE;
+                       Idqc = Xsdc;
+
+       case ATOM:      {
+                       char    *front, *temp, first; int clean;
+                       temp = front = (strflag ? ((char *) a) : a->a.pname);
+                       if(Idqc==0) Idqc = Xdqc;
+
+                       if(Idqc) {
+                               clean = first = *temp;
+                               first &= 0177;
+                               switch(QUTMASK & ctable[first]) {
+                               case QWNFRST:
+                               case QALWAYS:
+                                       clean = 0; break;
+                               case QWNUNIQ:
+                                       if(temp[1]==0) clean = 0;
+                               }
+                               if (first=='-'||first=='+') temp++;
+                               if(synclass(ctable[*temp])==VNUM) clean = 0;
+                               while (clean && *temp) {
+                                       if((ctable[*temp]&QUTMASK)==QALWAYS)
+                                               clean = 0;
+                                       else if(uctolc && (isupper(*temp)))
+                                               clean = 0;
+                                       temp++;
+                               }
+                               if (clean && !strflag)
+                                       fputs(front,useport);
+                               else     {
+                                       putc(Idqc,useport);
+                                       for(temp=front;*temp;temp++) {
+                                               if(  *temp==Idqc
+                                                 || (synclass(ctable[*temp])) == CESC)
+                                                       putc(Xesc,useport);
+                                               putc(*temp,useport);
+                                       }
+                                       putc(Idqc,useport);
+                               }
+
+                       }  else {
+                               register char *cp = front;
+                               int handy = ctable[*cp & 0177];
+
+                               if(synclass(handy)==CNUM)
+                                       putc(Xesc,useport);
+                               else switch(handy & QUTMASK) {
+                               case QWNUNIQ:
+                                       if(cp[1]==0) putc(Xesc,useport);
+                                       break;
+                               case QWNFRST:
+                               case QALWAYS:
+                                       putc(Xesc,useport);
+                               }
+                               for(; *cp; cp++) {
+                                       if((ctable[*cp]& QUTMASK)==QALWAYS)
+                                               putc(Xesc,useport);
+                                       putc(*cp,useport);
+                               }
+                       }
+               }
+       }
+}
+
+/* -- vectorpr
+ * (perhaps) print out vector specially
+ * this is called with a vector whose property list begins with
+ * a list.  We search for the 'print' property and if it exists,
+ * funcall the print function with two args: the vector and the port.
+ * We return TRUE iff we funcalled the function, else we return FALSE
+ * to have the standard printing done
+ */
+
+vectorpr(vec,port)
+register lispval vec;
+FILE *port;
+{
+    register lispval handy;
+    Savestack(2);
+
+
+    for ( handy = vec->v.vector[VPropOff]->d.cdr
+          ; handy != nil; handy = handy->d.cdr->d.cdr)
+    {
+       if (handy->d.car == Vprintsym)
+       {
+           lbot = np;
+           protect(handy->d.cdr->d.car);       /* function to call */
+           protect(vec);
+           protect(P(port));
+           Lfuncal();
+           Restorestack();
+           return(TRUE);       /* did the call */
+       }
+    }
+    Restorestack();
+    return(FALSE);     /* nothing printed */
+}
+           
+    
+    
+
+
+
+lfltpr(buf,val)                /* lisp floating point printer */
+char *buf;
+double val;
+{
+       register char *cp1; char *sprintf();
+
+       sprintf(buf,(char *)Vfloatformat->a.clb,val);
+       for(cp1 = buf; *cp1; cp1++)
+               if(*cp1=='.'|| *cp1=='E' || *cp1 == 'e') return;
+
+       /* if we are here, there was no dot, so the number was
+          an integer.  Furthermore, cp1 already points to the 
+          end of the string. */
+
+       *cp1++ = '.';
+       *cp1++ = '0';
+       *cp1++ = 0;
+}
+       
+
+/* dmpport ****************************************************************/
+/* outputs buffer indicated by first argument whether full or not      */
+
+dmpport(useport)
+FILE *useport;
+{
+       fflush(useport);
+}
+
+/*  protect and unprot moved to eval.c  (whr)  */
diff --git a/usr/src/ucb/lisp/franz/lam1.c b/usr/src/ucb/lisp/franz/lam1.c
new file mode 100644 (file)
index 0000000..473a550
--- /dev/null
@@ -0,0 +1,971 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam1.c,v 1.4 83/09/12 14:10:52 sklower Exp $";
+#endif
+
+/*                                     -[Fri Aug 12 07:28:13 1983 by jkf]-
+ *     lam1.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+# include "global.h"
+# include <sgtty.h>
+# include "chkrtab.h"
+# include "frame.h"
+
+lispval
+Leval()
+{
+       register lispval temp;
+
+       chkarg(1,"eval");
+       temp = lbot->val;
+           return(eval(temp));
+}
+
+lispval
+Lxcar()
+{      register int typ;
+       register lispval temp, result;
+
+       chkarg(1,"xcar");
+       temp = lbot->val;
+       if (((typ = TYPE(temp)) == DTPR) || (typ == ATOM) || HUNKP(temp))
+           return(temp->d.car);
+       else if(typ == SDOT) {
+               result = inewint(temp->i);
+               return(result);
+       } else if(Schainp!=nil && typ==ATOM)
+               return(nil);
+       else
+               return(error("Bad arg to car",FALSE));
+
+}
+
+lispval
+Lxcdr()
+{      register int typ;
+       register lispval temp;
+
+       chkarg(1,"xcdr");
+       temp = lbot->val;
+       if(temp==nil) return (nil);
+
+       if (((typ = TYPE(temp)) == DTPR) || HUNKP(temp)) 
+           return(temp->d.cdr);
+       else if(typ==SDOT) {
+               if(temp->s.CDR==0) return(nil);
+               temp = temp->s.CDR;
+               if(TYPE(temp)==DTPR)
+                   errorh1(Vermisc,"Fell off the end of a bignum",nil,FALSE,5,lbot->val);
+               return(temp);
+       } else if(Schainp!=nil && typ==ATOM)
+               return(nil);
+       else
+               return(error("Bad arg to cdr", FALSE));
+}
+
+lispval
+cxxr(as,ds)
+register int as,ds;
+{
+
+       register lispval temp, temp2;
+       int i, typ;
+       lispval errorh();
+
+       chkarg(1,"c{ad}+r");
+       temp = lbot->val;
+
+       for( i=0 ; i<ds ; i++)
+       {
+           if( temp != nil)
+           {
+               typ = TYPE(temp);
+               if ((typ == DTPR) || HUNKP(temp))
+                   temp = temp->d.cdr;
+               else
+                   if(typ==SDOT)
+                   {
+                       if(temp->s.CDR==0)
+                           temp = nil;
+                       else
+                           temp = temp->s.CDR;
+                       if(TYPE(temp)==DTPR)
+                           errorh1(Vermisc,"Fell off the end of a bignum",nil,FALSE,5,lbot->val);
+                   }
+               else
+                   if(Schainp!=nil && typ==ATOM)
+                       return(nil);
+               else
+                   return(errorh1(Vermisc,"Bad arg to cdr",nil,FALSE,5,temp));
+           }
+       }
+
+       for( i=0 ; i<as ; i++)
+       {
+           if( temp != nil )
+           {
+               typ = TYPE(temp);
+               if ((typ == DTPR) || HUNKP(temp))
+                   temp = temp->d.car;
+               else if(typ == SDOT)
+                       temp2 = inewint(temp->i), temp = temp2;
+               else if(Schainp!=nil && typ==ATOM)
+                   return(nil);
+               else
+                   return(errorh1(Vermisc,"Bad arg to car",nil,FALSE,5,temp));
+           }
+       }
+
+       return(temp);
+}
+
+lispval
+Lcar()
+{      return(cxxr(1,0)); }
+
+lispval
+Lcdr()
+{      return(cxxr(0,1)); }
+
+lispval
+Lcadr()
+{      return(cxxr(1,1)); }
+
+lispval
+Lcaar()
+{      return(cxxr(2,0)); }
+
+lispval
+Lc02r()
+{      return(cxxr(0,2)); }    /* cddr */
+
+lispval
+Lc12r()
+{      return(cxxr(1,2)); }    /* caddr */
+
+lispval
+Lc03r()
+{      return(cxxr(0,3)); }    /* cdddr */
+
+lispval
+Lc13r()
+{      return(cxxr(1,3)); }    /* cadddr */
+
+lispval
+Lc04r()
+{      return(cxxr(0,4)); }    /* cddddr */
+
+lispval
+Lc14r()
+{      return(cxxr(1,4)); }    /* caddddr */
+
+/*
+ *  
+ *     (nthelem num list)
+ *
+ * Returns the num'th element of the list, by doing a caddddd...ddr
+ * where there are num-1 d's. If num<=0 or greater than the length of
+ * the list, we return nil.
+ *
+ */
+
+lispval
+Lnthelem()
+{
+       register lispval temp;
+       register int i;
+
+       chkarg(2,"nthelem");
+
+       if( TYPE(temp = lbot->val) != INT)
+       return (error ("First arg to nthelem must be a fixnum",FALSE));
+
+       i = temp->i;    /* pick up the first arg */
+
+       if( i <= 0) return(nil);
+
+       ++lbot;                 /* fix lbot for call to cxxr() 'cadddd..r' */
+       temp = cxxr(1,i-1);
+       --lbot;
+
+       return(temp);
+}
+
+lispval
+Lscons()
+{
+       register struct argent *argp = lbot;
+       register lispval retp, handy;
+
+       chkarg(2,"scons");
+       retp = newsdot();
+       handy = (argp) -> val;
+       if(TYPE(handy)!=INT)
+               error("First arg to scons must be an int.",FALSE);
+       retp->s.I = handy->i;
+       handy = (argp+1)->val;
+       if(handy==nil)
+               retp->s.CDR = (lispval) 0;
+       else {
+               if(TYPE(handy)!=SDOT)
+                   error("Currently you may only link sdots to sdots.",FALSE);
+               retp->s.CDR = handy;
+       }
+       return(retp);
+}
+
+lispval
+Lbigtol(){
+       register lispval handy,newp;
+
+       chkarg(1,"Bignum-to-list");
+       handy = lbot->val;
+       while(TYPE(handy)!=SDOT)
+               handy = errorh1(Vermisc,
+                               "Non bignum argument to Bignum-to-list",
+                               nil,TRUE,5755,handy);
+       protect(newp = newdot());
+       while(handy) {
+               newp->d.car = inewint((long)handy->s.I);
+               if(handy->s.CDR==(lispval) 0) break;
+               newp->d.cdr = newdot();
+               newp = newp->d.cdr;
+               handy = handy->s.CDR;
+       }
+       handy = (--np)->val;
+       return(handy);
+}
+
+lispval
+Lcons()
+{
+       register lispval retp;
+       register struct argent *argp;
+
+       chkarg(2,"cons");
+       retp = newdot();
+       retp->d.car = ((argp = lbot) -> val);
+       retp->d.cdr = argp[1].val;
+       return(retp);
+}
+#define CA 0
+#define CD 1
+
+lispval
+rpla(what)
+int what;
+{      register struct argent *argp;
+       register int typ; register lispval first, second;
+
+       chkarg(2,"rplac[ad]");
+       argp = np-1;
+       first = (argp-1)->val;
+       while(first==nil)
+               first = error("Attempt to rplac[ad] nil.",TRUE);
+       second = argp->val;
+       if (((typ = TYPE(first)) == DTPR) || (typ == ATOM) || HUNKP(first)) {
+               if (what == CA)
+                       first->d.car = second;
+               else 
+                       first->d.cdr = second;
+               return(first);
+       }
+       if (typ==SDOT) {
+               if(what == CA) {
+                       typ = TYPE(second);
+                       if(typ!=INT) error("Rplacca of a bignum will only replace INTS",FALSE);
+                       first->s.I = second->i;
+               } else {
+                       if(second==nil)
+                               first->s.CDR = (lispval) 0;
+                       else
+                               first->s.CDR = second;
+               }
+               return(first);
+       }
+       return(error("Bad arg to rpla",FALSE));
+}
+lispval
+Lrplaca()
+{      return(rpla(CA));       }
+
+lispval
+Lrplacd()
+{      return(rpla(CD));       }
+
+
+lispval
+Leq()
+{
+       register struct argent *mynp = lbot + AD;
+
+       chkarg(2,"eq");
+       if(mynp->val==(mynp+1)->val) return(tatom);
+       return(nil);
+}
+
+
+
+lispval
+Lnull()
+{      chkarg(1,"null");
+       return ((lbot->val == nil) ? tatom : nil);
+}
+
+
+
+/* Lreturn **************************************************************/
+/* Returns the first argument - which is nill if not specified.                */
+
+lispval
+Lreturn()
+{
+       if(lbot==np) protect (nil);
+       Inonlocalgo(C_RET,lbot->val,nil);
+       /* NOT REACHED */
+}
+
+
+lispval
+Linfile()
+{
+       FILE *port;
+       register lispval name;
+
+       chkarg(1,"infile");
+       name = lbot->val;
+loop:
+       name = verify(name,"infile: file name must be atom or string");
+       /* return nil if file couldnt be opened
+       if ((port = fopen((char *)name,"r")) == NULL) return(nil); */   
+
+       if ((port = fopen((char *)name,"r")) == NULL) {
+               name = errorh1(Vermisc,"Unable to open file for reading.",nil,TRUE,31,name);
+               goto loop;
+       }
+       ioname[PN(port)] = (lispval) inewstr((char *)name); /* remember name */
+       return(P(port));
+}
+
+/* outfile - open a file for writing.  
+ * 27feb81 [jkf] - modifed to accept two arguments, the second one being a
+ *   string or atom, which if it begins with an `a' tells outfile to open the
+ *   file in append mode
+ */
+lispval
+Loutfile()
+{
+       FILE *port; register lispval name;
+       char *mode ="w";    /* mode is w for create new file, a for append */
+       char *given;
+
+       if(lbot+1== np) protect(nil);
+       chkarg(2,"outfile");
+       name = lbot->val;
+       given = (char *)verify((lbot+1)->val,"Illegal file open mode.");
+       if(*given == 'a') mode = "a";
+loop:
+       name = verify(name,"Please supply atom or string name for port.");
+#ifdef os_vms
+       /*
+        *      If "w" mode, open it as a "txt" file for convenience in VMS
+        */
+       if (strcmp(mode,"w") == 0) {
+               int fd;
+
+               if ((fd = creat(name,0777,"txt")) < 0) {
+                       name = errorh1(Vermisc,"Unable to open file for writing.",nil,TRUE,31,name);
+                       goto loop;
+               }
+               port = fdopen(fd,mode);
+       } else
+#endif
+       if ((port = fopen((char *)name,mode)) == NULL) {
+               name = errorh1(Vermisc,"Unable to open file for writing.",nil,TRUE,31,name);
+               goto loop;
+       }
+       ioname[PN(port)] = (lispval) inewstr((char *)name);
+       return(P(port));
+}
+
+lispval
+Lterpr()
+{
+       register lispval handy;
+       FILE *port;
+
+       if(lbot==np) handy = nil;
+       else 
+       { 
+           chkarg(1,"terpr");
+           handy = lbot->val;
+       }
+
+       port = okport(handy,okport(Vpoport->a.clb,stdout));
+       putc('\n',port);
+       fflush(port);
+       return(nil);
+}
+
+lispval
+Lclose()
+{
+       lispval port;
+
+       chkarg(1,"close");
+       port = lbot->val;
+       if((TYPE(port))==PORT) {
+               fclose(port->p);
+               ioname[PN(port->p)] = nil;
+               return(tatom);
+       }
+       errorh1(Vermisc,"close:Non-port",nil,FALSE,987,port);
+}
+
+lispval
+Ltruename()
+{
+    chkarg(1,"truename");
+    if(TYPE(lbot->val) != PORT)
+       errorh1(Vermisc,"truename: non port argument",nil,FALSE,0,lbot->val);
+
+    return(ioname[PN(lbot->val->p)]);
+}
+
+lispval
+Lnwritn()
+{
+       register FILE *port;
+       register value;
+       register lispval handy;
+
+       if(lbot==np) handy = nil;
+       else 
+       {
+           chkarg(1,"nwritn");
+           handy = lbot->val;
+       }
+
+       port = okport(handy,okport(Vpoport->a.clb,stdout));
+       value = port->_ptr - port->_base;
+       return(inewint(value));
+}
+
+lispval
+Ldrain()
+{
+       register FILE *port;
+       register int iodes;
+       register lispval handy;
+       struct sgttyb arg;
+
+       if(lbot==np) handy = nil;
+       else 
+       {
+           chkarg(1,"nwritn");
+           handy = lbot->val;
+       }
+       port = okport(handy, okport(Vpoport->a.clb,stdout));
+       if(port->_flag & _IOWRT) {
+               fflush(port);
+               return(nil);
+       }
+       if(! port->_flag & _IOREAD) return(nil);
+       port->_cnt = 0;
+       port->_ptr = port->_base;
+       iodes = fileno(port);
+       if(gtty(iodes,&arg) != -1) stty(iodes,&arg);
+       return((lispval)(xports + (port - _iob)));
+}
+
+lispval
+Llist()
+{
+       /* added for the benefit of mapping functions. */
+       register struct argent *ulim, *namptr;
+       register lispval temp, result;
+       Savestack(4);
+
+       ulim = np;
+       namptr = lbot + AD;
+       temp = result = (lispval) np;
+       protect(nil);
+       for(; namptr < ulim;) {
+               temp = temp->l = newdot();
+               temp->d.car = (namptr++)->val;
+       }
+       temp->l = nil;
+       Restorestack();
+       return(result->l);
+}
+
+lispval
+Lnumberp()
+{
+       chkarg(1,"numberp");
+       switch(TYPE(lbot->val)) {
+       case INT: case DOUB: case SDOT:
+               return(tatom);
+       }
+       return(nil);
+}
+
+lispval
+Latom()
+{
+       register struct argent *lb = lbot;
+       chkarg(1,"atom");
+       if(TYPE(lb->val)==DTPR || (HUNKP(lb->val)))
+               return(nil);
+       else
+               return(tatom);
+}
+
+lispval
+Ltype()
+{
+       chkarg(1,"type");
+       switch(TYPE(lbot->val)) {
+       case INT:
+               return(int_name);
+       case ATOM:
+               return(atom_name);
+       case SDOT:
+               return(sdot_name);
+       case DOUB:
+               return(doub_name);
+       case DTPR:
+               return(dtpr_name);
+       case STRNG:
+               return(str_name);
+       case ARRAY:
+               return(array_name);
+       case BCD:
+               return(funct_name);
+       case OTHER:
+               return(other_name);
+
+       case HUNK2:
+               return(hunk_name[0]);
+       case HUNK4:
+               return(hunk_name[1]);
+       case HUNK8:
+               return(hunk_name[2]);
+       case HUNK16:
+               return(hunk_name[3]);
+       case HUNK32:
+               return(hunk_name[4]);
+       case HUNK64:
+               return(hunk_name[5]);
+       case HUNK128:
+               return(hunk_name[6]);
+               
+       case VECTOR:
+               return(vect_name);
+       case VECTORI:
+               return(vecti_name);
+
+       case VALUE:
+               return(val_name);
+       case PORT:
+               return(port_name);
+       }
+       return(nil);
+}
+
+lispval
+Ldtpr()
+{
+       chkarg(1,"dtpr");
+       return(typred(DTPR, lbot->val));
+}
+
+lispval
+Lbcdp()
+{
+       chkarg(1,"bcdp");
+       return(typred(BCD, lbot->val));
+}
+
+lispval
+Lportp()
+{
+       chkarg(1,"portp");
+       return(typred(PORT, lbot->val));
+}
+
+lispval
+Larrayp()
+{
+       chkarg(1,"arrayp");
+       return(typred(ARRAY, lbot->val));
+}
+
+/*
+ *     (hunkp 'g_arg1)
+ * Returns t if g_arg1 is a hunk, otherwise returns nil.
+ */
+
+lispval
+Lhunkp()
+{
+       chkarg(1,"hunkp");
+       if (HUNKP(lbot->val))
+               return(tatom);          /* If a hunk, return t */
+       else
+               return(nil);            /* else nil */
+}
+
+lispval
+Lset()
+{
+       lispval varble;
+
+       chkarg(2,"set");
+       varble = lbot->val;
+       switch(TYPE(varble))
+               {
+       case ATOM:      return(varble->a.clb = lbot[1].val);
+
+       case VALUE:     return(varble->l = lbot[1].val);
+               }
+
+       error("IMPROPER USE OF SET",FALSE);
+       /* NOTREACHED */
+}
+
+lispval
+Lequal()
+{
+       register lispval first, second;
+       register type1, type2;
+       lispval Lsub(),Lzerop();
+       long *oldsp;
+       Keepxs();
+       chkarg(2,"equal");
+
+
+       if(lbot->val==lbot[1].val) return(tatom);
+
+       oldsp=sp(); stack((long)lbot->val);stack((long)lbot[1].val);
+       for(;oldsp > sp();) {
+
+           first = (lispval) unstack(); second = (lispval) unstack();
+    again:
+           if(first==second) continue;
+
+           type1=TYPE(first); type2=TYPE(second);
+           if(type1!=type2) {
+               if((type1==SDOT&&type2==INT)||(type1==INT&&type2==SDOT))
+                   goto dosub;
+               {Freexs(); return(nil);}
+           }
+           switch(type1) {
+           case DTPR:
+               stack((long)first->d.cdr); stack((long)second->d.cdr);
+               first = first->d.car; second = second->d.car;
+               goto again;
+           case DOUB:
+               if(first->r!=second->r)
+                   {Freexs(); return(nil);}
+               continue;
+           case INT:
+               if(first->i!=second->i)
+                   {Freexs(); return(nil);}
+               continue;
+           case VECTOR:
+               if(!vecequal(first,second)) {Freexs(); return(nil);}
+               continue;
+           case VECTORI:
+               if(!veciequal(first,second)) {Freexs(); return(nil);}
+               continue;
+    dosub:
+           case SDOT: {
+               lispval temp;
+               struct argent *OLDlbot = lbot;
+               lbot = np;
+               np++->val = first;
+               np++->val = second;
+               temp = Lsub();
+               np = lbot;
+               lbot = OLDlbot;
+               if(TYPE(temp)!=INT || temp->i!=0)
+                   {Freexs(); return(nil);}
+               }
+               continue;
+           case VALUE:
+               if(first->l!=second->l)
+                   {Freexs(); return(nil);}
+               continue;
+           case STRNG:
+               if(strcmp((char *)first,(char *)second)!=0)
+                   {Freexs(); return(nil);}
+               continue;
+
+           default:
+               {Freexs(); return(nil);}
+           }
+       }
+       {Freexs(); return(tatom);}
+}
+lispval
+oLequal()
+{
+       chkarg(2,"equal");
+
+       if( lbot[1].val == lbot->val ) return(tatom);
+       if(Iequal(lbot[1].val,lbot->val)) return(tatom); else return(nil);
+}
+
+Iequal(first,second) 
+register lispval first, second;
+{
+       register type1, type2;
+       lispval Lsub(),Lzerop();
+
+       if(first==second)
+               return(1);
+       type1=TYPE(first);
+       type2=TYPE(second);
+       if(type1!=type2) {
+               if((type1==SDOT&&type2==INT)||(type1==INT&&type2==SDOT))
+                       goto dosub;
+               return(0);
+       }
+       switch(type1) {
+       case DTPR:
+                return(
+                       Iequal(first->d.car,second->d.car) &&
+                       Iequal(first->d.cdr,second->d.cdr) );
+       case DOUB:
+               return(first->r==second->r);
+       case INT:
+               return( (first->i==second->i));
+dosub:
+       case SDOT:
+       {
+               lispval temp;
+               struct argent *OLDlbot = lbot;
+               lbot = np;
+               np++->val = first;
+               np++->val = second;
+               temp = Lsub();
+               np = lbot;
+               lbot = OLDlbot;
+               return(TYPE(temp)==INT&& temp->i==0);
+       }
+       case VALUE:
+               return( first->l==second->l );
+       case STRNG:
+               return(strcmp((char *)first,(char *)second)==0);
+       }
+       return(0);
+}
+lispval
+Zequal()
+{
+       register lispval first, second;
+       register type1, type2;
+       lispval Lsub(),Lzerop();
+       long *oldsp;
+       Keepxs();
+       chkarg(2,"equal");
+
+
+       if(lbot->val==lbot[1].val) return(tatom);
+
+       oldsp=sp(); stack((long)lbot->val);stack((long)lbot[1].val);
+
+       for(;oldsp > sp();) {
+
+           first = (lispval) unstack(); second = (lispval) unstack();
+    again:
+           if(first==second) continue;
+
+           type1=TYPE(first); type2=TYPE(second);
+           if(type1!=type2) {
+               if((type1==SDOT&&type2==INT)||(type1==INT&&type2==SDOT))
+                   goto dosub;
+               {Freexs(); return(nil);}
+           }
+           switch(type1) {
+           case DTPR:
+               stack((long)first->d.cdr); stack((long)second->d.cdr);
+               first = first->d.car; second = second->d.car;
+               goto again;
+           case DOUB:
+               if(first->r!=second->r)
+                   {Freexs(); return(nil);}
+               continue;
+           case INT:
+               if(first->i!=second->i)
+                   {Freexs(); return(nil);}
+               continue;
+    dosub:
+           case SDOT:
+           {
+               lispval temp;
+               struct argent *OLDlbot = lbot;
+               lbot = np;
+               np++->val = first;
+               np++->val = second;
+               temp = Lsub();
+               np = lbot;
+               lbot = OLDlbot;
+               if(TYPE(temp)!=INT || temp->i!=0)
+                   {Freexs(); return(nil);}
+           }
+               continue;
+           case VALUE:
+               if(first->l!=second->l)
+                   {Freexs(); return(nil);}
+               continue;
+           case STRNG:
+               if(strcmp((char *)first,(char *)second)!=0)
+                   {Freexs(); return(nil);}
+               continue;
+           }
+       }
+       {Freexs(); return(tatom);}
+}
+
+/*
+ * (print 'expression ['port]) prints the given expression to the given
+ * port or poport if no port is given.  The amount of structure
+ * printed is a function of global lisp variables plevel and
+ * plength.
+ */
+lispval
+Lprint()
+{
+       register lispval handy;
+       extern int plevel,plength;
+
+
+       handy = nil;                    /* port is optional, default nil */
+       switch(np-lbot) 
+       {
+           case 2: handy = lbot[1].val;
+           case 1: break;
+           default: argerr("print");
+       }
+
+       chkrtab(Vreadtable->a.clb);
+       if(TYPE(Vprinlevel->a.clb) == INT)
+       { 
+          plevel = Vprinlevel->a.clb->i;
+       }
+       else plevel = -1;
+       if(TYPE(Vprinlength->a.clb) == INT)
+       {
+           plength = Vprinlength->a.clb->i;
+       }
+       else plength = -1;
+       printr(lbot->val,okport(handy,okport(Vpoport->a.clb,poport)));
+       return(nil);
+}
+
+/* patom does not use plevel or plength 
+ *
+ * form is (patom 'value ['port])
+ */
+lispval
+Lpatom()
+{
+       register lispval temp;
+       register lispval handy;
+       register int typ;
+       FILE *port;
+
+       handy = nil;                    /* port is optional, default nil */
+       switch(np-lbot) 
+       {
+           case 2: handy = lbot[1].val;
+           case 1: break;
+           default: argerr("patom");
+       }
+
+       temp = Vreadtable->a.clb;
+       chkrtab(temp);
+       port = okport(handy, okport(Vpoport->a.clb,stdout));
+       if ((typ= TYPE((temp = (lbot)->val))) == ATOM)
+               fputs(temp->a.pname, port);
+       else if(typ == STRNG)
+               fputs((char *)temp,port);
+       else
+       {
+               if(TYPE(Vprinlevel->a.clb) == INT)
+               {
+                   plevel = Vprinlevel->a.clb->i;
+               }
+               else plevel = -1;
+               if(TYPE(Vprinlength->a.clb) == INT)
+               {
+                   plength = Vprinlength->a.clb->i;
+               }
+               else plength = -1;
+
+               printr(temp, port);
+       }
+       return(temp);
+}
+
+/*
+ * (pntlen thing) returns the length it takes to print out
+ * an atom or number.
+ */
+
+lispval
+Lpntlen()
+{
+       return(inewint((long)Ipntlen()));
+}
+Ipntlen()
+{
+       register lispval temp;
+       register char *handy;
+       char *sprintf();
+
+       temp = np[-1].val;
+loop:  switch(TYPE(temp)) {
+
+       case ATOM:
+               handy = temp->a.pname;
+               break;
+
+       case STRNG:
+               handy = (char *) temp;
+               break;
+
+       case INT:
+               sprintf(strbuf,"%d",temp->i);
+               handy =strbuf;
+               break;
+
+       case DOUB:
+               sprintf(strbuf,"%g",temp->r);
+               handy =strbuf;
+               break;
+
+       default:
+               temp = error("Non atom or number to pntlen\n",TRUE);
+               goto loop;
+       }
+
+       return( strlen(handy));
+}
+#undef okport
+FILE *
+okport(arg,proper) 
+lispval arg;
+FILE *proper;
+{
+       if(TYPE(arg)!=PORT)
+               return(proper);
+       else
+               return(arg->p);
+}
diff --git a/usr/src/ucb/lisp/franz/lam2.c b/usr/src/ucb/lisp/franz/lam2.c
new file mode 100644 (file)
index 0000000..5104862
--- /dev/null
@@ -0,0 +1,680 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: /na/franz/franz/RCS/lam2.c,v 1.3 83/08/06 08:37:23 jkf Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:46:16 1983 by jkf]-
+ *     lam2.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+# include "global.h"
+# include <signal.h>
+# include "structs.h"
+# include "chars.h"
+# include "chkrtab.h"
+/*
+ * (flatc 'thing ['max]) returns the smaller of max and the number of chars
+ * required to print thing linearly.
+ * if max argument is not given, we assume the second arg is infinity
+ */
+static flen; /*Internal to this module, used as a running counter of flatsize*/
+static fmax; /*used for maximum for quick reference */
+char *strcpy();
+
+lispval
+Lflatsi()
+{
+       register lispval current;
+       Savestack(1);                   /* fixup entry mask */
+
+       fmax = 0x7fffffff;      /* biggest integer by default */
+       switch(np-lbot) 
+       {
+           case 2: current = lbot[1].val;
+                   while(TYPE(current) != INT)
+                       current = errorh1(Vermisc,
+                                       "flatsize: second arg not integer",
+                                       nil,TRUE,0,current);
+                   fmax = current->i;
+           case 1: break;
+           default: argerr("flatsize");
+       }
+
+       flen = 0; 
+       current = lbot->val;
+       protect(nil);                   /*create space for argument to pntlen*/
+       Iflatsi(current);
+       Restorestack();
+       return(inewint(flen));
+}
+/*
+ * Iflatsi does the real work of the calculation for flatc
+ */
+Iflatsi(current)
+register lispval current;
+{
+
+       if(flen > fmax) return;
+       switch(TYPE(current)) {
+
+       patom:
+       case INT: case ATOM: case DOUB: case STRNG:
+               np[-1].val = current;
+               flen += Ipntlen();
+               return;
+       
+       pthing:
+       case DTPR:
+               flen++;
+               Iflatsi(current->d.car);
+               current = current->d.cdr;
+               if(current == nil) {
+                       flen++;
+                       return;
+               }
+               if(flen > fmax) return;
+               switch(TYPE(current)) {
+               case INT: case ATOM: case DOUB:
+                       flen += 4;
+                       goto patom;
+               case DTPR:
+                       goto pthing;
+               }
+       }
+}
+
+
+#define EADC -1
+#define EAD  -2
+lispval
+Lread()
+{ return (r(EAD)); }
+
+lispval
+Lratom()
+{ return (r(ATOM)); }
+
+lispval
+Lreadc()
+{ return (r(EADC)); }
+
+
+extern unsigned char *ctable;
+/* r *********************************************************************/
+/* this function maps the desired read         function into the system-defined */
+/* reading functions after testing for a legal port.                    */
+lispval
+r(op)
+int op;
+{
+       unsigned char c; register lispval result;
+       register cc;
+       int orlevel; extern int rlevel;
+       FILE *ttemp;
+       struct nament *oldbnp = bnp;
+       Savestack(2);
+
+       switch(np-lbot) {
+       case 0:
+               protect(nil);
+       case 1:
+               protect(nil);
+       case 2: break;
+       default:
+               argerr("read or ratom or readc");
+       }
+       result = Vreadtable->a.clb;
+       chkrtab(result);
+       orlevel = rlevel;
+       rlevel = 0;
+       ttemp = okport(Vpiport->a.clb,stdin);
+       ttemp = okport(lbot->val,ttemp);
+/*printf("entering switch\n");*/
+       if(ttemp == stdin) fflush(stdout);      /* flush any pending 
+                                                * characters if reading stdin 
+                                                * there should be tests to see
+                                                * if this is a tty or pipe
+                                                */
+
+       switch (op)
+       {
+       case EADC:      rlevel = orlevel;
+                       cc = getc(ttemp);
+                       c = cc;
+                       if(cc == EOF)
+                       {
+                               Restorestack();
+                               return(lbot[1].val);
+                       } else {
+                               strbuf[0] = hash = (c & 0177);
+                               strbuf[1] = 0;
+                               atmlen = 2;
+                               Restorestack();
+                               return((lispval)getatom(TRUE));
+                       }
+
+       case ATOM:      rlevel = orlevel;
+                       result = (ratomr(ttemp));
+                       goto out;
+
+       case EAD:       PUSHDOWN(Vpiport,P(ttemp)); /* rebind Vpiport */
+                       result = readr(ttemp);
+       out:            if(result==eofa)
+                       {    
+                            if(sigintcnt > 0) sigcall(SIGINT);
+                            result = lbot[1].val;
+                       }
+                       rlevel = orlevel;
+                       popnames(oldbnp);       /* unwind bindings */
+                       Restorestack();
+                       return(result);
+       }
+       /* NOTREACHED */
+}
+
+/* Lload *****************************************************************/
+/* Reads in and executes forms from the specified file. This should      */
+/* really be an nlambda taking multiple arguments, but the error        */
+/* handling gets funny in that case (one file out of several not        */
+/* openable, for instance).                                             */
+lispval
+Lload()
+{
+       register FILE *port;
+       register char *p, *ttemp; register lispval vtemp;
+       struct nament *oldbnp = bnp;
+       int orlevel,typ;
+       char longname[100];
+       char *shortname, *end2, *Ilibdir();
+       /*Savestack(4); not necessary because np not altered */
+
+       chkarg(1,"load");
+       if((typ = TYPE(lbot->val)) == ATOM)
+           ttemp =  lbot->val->a.pname ;  /* ttemp will point to name */
+       else if(typ == STRNG)
+           ttemp = (char *) lbot->val;
+       else 
+            return(error("FILENAME MUST BE ATOMIC",FALSE));
+       strcpy(longname, Ilibdir());
+       for(p = longname; *p; p++);
+       *p++ = '/'; *p = 0;
+       shortname = p;
+       strcpy(p,ttemp);
+       for(; *p; p++);
+               end2 = p;
+       strcpy(p,".l");
+       if ((port = fopen(shortname,"r")) == NULL &&
+               (port = fopen(longname, "r")) == NULL) {
+                       *end2 = 0;
+                       if ((port = fopen(shortname,"r")) == NULL &&
+                               (port = fopen(longname, "r")) == NULL)
+                                       errorh1(Vermisc,"Can't open file: ", 
+                                                    nil,FALSE,0,lbot->val);
+       }
+       orlevel = rlevel;
+       rlevel = 0;
+
+       if(ISNIL(copval(gcload,CNIL)) &&
+               loading->a.clb != tatom &&
+               ISNIL(copval(gcdis,CNIL)))
+               gc((struct types *)CNIL);    /*  do a gc if gc will be off  */
+
+       /* shallow bind the value of lisp atom piport   */
+       /* so readmacros will work                      */
+       PUSHDOWN(Vpiport,P(port));
+       PUSHDOWN(loading,tatom);        /* set indication of loading status */
+
+       while ((vtemp = readr(port)) != eofa) {
+           eval(vtemp);
+       }
+       popnames(oldbnp);               /* unbind piport, loading */
+
+       rlevel = orlevel;
+       fclose(port);
+       return(nil);
+}
+
+/* concat **************************************************
+-
+-  use: (concat arg1 arg2 ... )
+-
+-  concatenates the print names of all of its arguments.
+- the arguments may be atoms, integers or real numbers.
+-
+- *********************************************************/
+lispval
+Iconcat(unintern)
+{
+       char *sprintf();
+       register struct argent *temnp;
+       register int atmlen; /* Passt auf!  atmlen in the external
+                               sense calculated by newstr          */
+       lispval cur;
+
+       atmlen = 0 ;    
+       strbuf[0] = NULL_CHAR ;
+
+       /* loop for each argument */
+       for(temnp = lbot + AD ; temnp < np ; temnp++)
+       {
+           cur = temnp->val;
+      loop: if(atmlen > 512) error("concat: string buffer overflow",FALSE);
+           switch(TYPE(cur))
+           {
+           case ATOM:
+                strcpy(&strbuf[atmlen], ((struct atom *) cur) -> pname) ;
+                break;
+
+           case STRNG:
+                strcpy(&strbuf[atmlen], (char *) cur);
+                break;
+
+           case INT:
+                sprintf(&strbuf[atmlen],"%d",cur->i);
+                break;
+
+           case DOUB:
+                sprintf(&strbuf[atmlen],"%f",cur->f);
+                break;
+
+           case SDOT: {
+               struct _iobuf _myiob;
+
+               _myiob._flag = _IOWRT+_IOSTRG;
+               _myiob._ptr = &strbuf[atmlen];
+               _myiob._cnt = STRBLEN - 1  - atmlen;
+
+               pbignum(cur,&_myiob);
+               putc(0,&_myiob);
+               break; }
+                   
+           default:
+                cur = error("Non atom or number to concat",TRUE);
+                goto loop;    /* if returns value, try it */
+          }
+          atmlen = strlen(strbuf);
+
+       }
+
+       if(unintern)
+               return( (lispval) newatom(FALSE)); /* uninterned atoms may
+                                                       have printname gc'd*/
+       else
+               return( (lispval) getatom(FALSE)) ;
+}
+lispval
+Lconcat(){
+       return(Iconcat(FALSE));
+}
+lispval
+Luconcat(){
+       return(Iconcat(TRUE));
+}
+
+lispval
+Lputprop()
+{
+       lispval Iputprop();
+       chkarg(3,"putprop");
+       return(Iputprop(lbot->val,lbot[1].val,lbot[2].val));
+}
+
+/*
+ * Iputprop :internal version of putprop used by some C functions
+ *  note: prop and ind are lisp values but are not protected (by this
+ * function) from gc.  The caller should protect them!!
+ */
+lispval
+Iputprop(atm,prop,ind)
+register lispval prop, ind, atm;
+{
+       register lispval pptr;
+       lispval *tack;          /* place to begin property list */
+       lispval pptr2;
+       lispval errorh();
+       Savestack(4);
+       
+ top:
+       switch (TYPE(atm)) {
+       case ATOM:
+               if(atm == nil) tack = &nilplist;
+               else tack =  &(atm->a.plist);
+               break;
+       case DTPR:
+               for (pptr = atm->d.cdr ; pptr != nil ; pptr = pptr->d.cdr->d.cdr)
+                   if(TYPE(pptr) != DTPR || TYPE(pptr->d.cdr) != DTPR) break;
+               if(pptr != nil) 
+               {   atm = errorh1(Vermisc,
+                                "putprop: bad disembodied property list",
+                                nil,TRUE,0,atm);
+                   goto top;
+               }
+               tack = (lispval *) &(atm->d.cdr);
+               break;
+       default:
+               errorh1(Vermisc,"putprop: Bad first argument: ",nil,FALSE,0,atm);
+       }
+       pptr = *tack;   /* start of property list */
+/*findit:*/
+       for (pptr = *tack ; pptr != nil ; pptr = pptr->d.cdr->d.cdr)
+               if (pptr->d.car == ind) {
+                       (pptr->d.cdr)->d.car = prop;
+                       Restorestack();
+                       return(prop);
+               }
+       /* not found, add to front
+          be careful, a gc could occur before the second newdot() */
+          
+       pptr = newdot();
+       pptr->d.car = prop;
+       pptr->d.cdr = *tack;
+       protect(pptr);
+       pptr2 = newdot();
+       pptr2->d.car = ind;
+       pptr2->d.cdr = pptr;
+       *tack = pptr2;
+       Restorestack();
+       return(prop);
+}
+
+/* get from property list 
+ *   there are three routines to accomplish this
+ *     Lget - lisp callable, the first arg can be a symbol or a disembodied
+ *           property list.  In the latter case we check to make sure it
+ *           is a real one (as best we can).
+ *     Iget - internal routine, the first arg must be a symbol, no disembodied
+ *           plists allowed
+ *     Igetplist - internal routine, the first arg is the plist to search.
+ */
+lispval
+Lget()
+{
+       register lispval ind, atm;
+       register lispval dum1;
+       lispval Igetplist();
+
+       chkarg(2,"get");
+       ind = lbot[1].val;
+       atm = lbot[0].val;
+top:
+       switch(TYPE(atm)) {
+       case ATOM:
+               if(atm==nil) atm = nilplist;
+               else atm = atm->a.plist;
+               break;          
+
+       case DTPR:
+               for (dum1 = atm->d.cdr; dum1 != nil; dum1 = dum1->d.cdr->d.cdr)
+                   if((TYPE(dum1) != DTPR) || 
+                      (TYPE(dum1->d.cdr) != DTPR)) break; /* bad prop list */
+               if(dum1 != nil) 
+               {   atm = errorh1(Vermisc,
+                                "get: bad disembodied property list",
+                                nil,TRUE,0,atm);
+                   goto top;
+               }
+               atm = atm->d.cdr;
+               break;
+       default:
+               /* remove since maclisp doesnt treat
+                  this as an error, ugh
+                  return(errorh1(Vermisc,"get: bad first argument: ",
+                              nil,FALSE,0,atm));
+                */
+                return(nil);
+       }
+
+       while (atm != nil)
+               {
+                       if (atm->d.car == ind)
+                               return ((atm->d.cdr)->d.car);
+                       atm = (atm->d.cdr)->d.cdr;
+               }
+       return(nil);
+}
+/*
+ * Iget - the first arg must be a symbol.
+ */
+       
+lispval
+Iget(atm,ind)
+register lispval atm, ind;
+{
+       lispval Igetplist();
+
+       if(atm==nil)
+               atm = nilplist;
+       else
+               atm = atm->a.plist;
+       return(Igetplist(atm,ind));
+}
+
+/*
+ *  Igetplist
+ * pptr is a plist
+ * ind is the indicator
+ */
+
+lispval
+Igetplist(pptr,ind)
+register lispval pptr,ind;
+{
+       while (pptr != nil)
+               {
+                       if (pptr->d.car == ind)
+                               return ((pptr->d.cdr)->d.car);
+                       pptr = (pptr->d.cdr)->d.cdr;
+               }
+       return(nil);
+}
+lispval
+Lgetd()
+{
+       register lispval typ;
+       
+       chkarg(1,"getd");
+       typ = lbot->val;
+       if (TYPE(typ) != ATOM) 
+          errorh1(Vermisc,
+                 "getd: Only symbols have function definitions",
+                 nil,
+                 FALSE,
+                 0,
+                 typ);
+       return(typ->a.fnbnd);
+}
+lispval
+Lputd()
+{
+       register lispval atom, list;
+       
+       chkarg(2,"putd");
+       list = lbot[1].val;
+       atom = lbot->val;
+       if (TYPE(atom) != ATOM) error("only symbols have function definitions",
+                                       FALSE);
+       atom->a.fnbnd = list;
+       return(list);
+}
+
+/* ===========================================================
+- mapping functions which return a list of the answers
+- mapcar applies the given function to successive elements
+- maplist applies the given function to successive sublists
+- ===========================================================*/
+
+lispval
+Lmapcrx(maptyp,join)
+int maptyp;            /* 0 = mapcar,  1 = maplist  */
+int join;              /* 0 = the above, 1 = s/car/can/ */
+{
+       register struct argent *namptr;
+       register index;
+       register lispval temp;
+       register lispval current;
+
+       struct argent *first, *last;
+       int count;
+       lispval lists[25], result;
+       Savestack(4);
+       
+       namptr = lbot + 1;
+       count = np - namptr;
+       if (count <= 0) return (nil);
+       result = current =  (lispval) np;
+       protect(nil);                   /* set up space for returned list */
+       protect(lbot->val);     /*copy funarg for call to funcall */
+       lbot = np -1;
+       first = np;
+       last = np += count;
+       for(index = 0; index < count; index++) {
+               temp =(namptr++)->val; 
+               if (TYPE (temp ) != DTPR && temp!=nil) 
+                       error ( "bad list argument to map",FALSE);
+               lists[index] = temp;
+       }
+       for(;;) {
+               for(namptr=first,index=0; index<count; index++) {
+                       temp = lists[index];
+                       if(temp==nil) goto done;
+
+                       if(maptyp==0) (namptr++)->val = temp->d.car;
+                       else (namptr++)->val = temp;
+
+                       lists[index] = temp->d.cdr;
+               }
+               if (join == 0) {
+                       current->l = newdot();
+                       current->l->d.car = Lfuncal();
+                       current = (lispval) &current->l->d.cdr;
+               } else {
+                       current->l = Lfuncal();
+                       if ( TYPE ( current -> l) != DTPR && current->l != nil)
+                               error("bad type returned from funcall inside map",FALSE);
+                       else  while ( current -> l  != nil )
+                                       current = (lispval) & (current ->l ->d.cdr);
+               }
+               np = last;
+       }
+done:  if (join == 0)current->l = nil;
+       Restorestack();
+       return(result->l);
+}
+
+/* ============================
+-
+- Lmapcar
+- =============================*/
+
+lispval
+Lmapcar()
+{
+       return(Lmapcrx(0,0));   /* call general routine */
+}
+
+
+/* ============================
+-
+-
+-  Lmaplist
+- ==============================*/
+
+lispval
+Lmaplist()
+{
+       return(Lmapcrx(1,0));   /* call general routine */
+}
+
+
+/* ================================================
+- mapping functions which return the value of the last function application.
+- mapc and map
+- ===================================================*/
+
+lispval
+Lmapcx(maptyp)
+int maptyp;            /* 0= mapc   , 1= map  */
+{
+       register struct argent *namptr;
+       register index;
+       register lispval temp;
+       register lispval result;
+
+       int count;
+       struct argent *first;
+       lispval lists[25], errorh();
+       Savestack(4);
+       
+       namptr = lbot + 1;
+       count = np - namptr;
+       if(count <= 0) return(nil);
+       result = lbot[1].val;           /*This is what macsyma wants so ... */
+                                       /*copy funarg for call to funcall */
+       lbot = np; protect((namptr - 1)->val);
+       first = np; np += count;
+
+       for(index = 0; index < count; index++) {
+               temp = (namptr++)->val;
+               while(temp!=nil && TYPE(temp)!=DTPR)
+                       temp = errorh1(Vermisc,"Inappropriate list argument to mapc",nil,TRUE,0,temp);
+               lists[index] = temp;
+       }
+       for(;;) {
+               for(namptr=first,index=0; index<count; index++) {
+                       temp = lists[index];
+                       if(temp==nil)
+                               goto done;
+                       if(maptyp==0)
+                               (namptr++)->val = temp->d.car;
+                       else
+                               (namptr++)->val = temp;
+                       lists[index] = temp->d.cdr;
+               }
+               Lfuncal();
+       }
+done:  
+       Restorestack();
+       return(result);
+}
+
+
+/* ==================================
+-
+-      mapc   map the car of the lists
+-
+- ==================================*/
+
+lispval
+Lmapc()
+{      return( Lmapcx(0) );  }
+
+
+/* =================================
+-
+-      map    map the cdr of the lists
+-
+- ===================================*/
+
+lispval
+Lmap()
+{      return( Lmapcx(1) );   }
+
+
+lispval
+Lmapcan()
+{ 
+       lispval Lmapcrx();
+
+       return ( Lmapcrx ( 0,1 ) ); 
+} 
+
+lispval
+Lmapcon()
+{ 
+       lispval Lmapcrx();
+
+       return ( Lmapcrx ( 1,1 ) ); 
+}
diff --git a/usr/src/ucb/lisp/franz/lam3.c b/usr/src/ucb/lisp/franz/lam3.c
new file mode 100644 (file)
index 0000000..63a9787
--- /dev/null
@@ -0,0 +1,587 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: /na/franz/franz/RCS/lam3.c,v 1.2 83/08/06 08:37:32 jkf Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:47:19 1983 by jkf]-
+ *     lam3.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+# include "global.h"
+# include "chars.h"
+# include "chkrtab.h"
+
+lispval
+Lalfalp()
+{
+       register char  *first, *second;
+
+       chkarg(2,"alphalessp");
+       first = (char *) verify(lbot->val,"alphalessp: non symbol or string arg");
+       second = (char *) verify((lbot+1)->val,"alphalessp: non symbol or string arg");
+       if(strcmp(first,second) < 0)
+               return(tatom);
+       else
+               return(nil);
+}
+
+lispval
+Lncons()
+{
+       register lispval handy;
+
+       chkarg(1,"ncons");
+       handy = newdot();
+       handy->d.cdr = nil;
+       handy->d.car = lbot->val;
+       return(handy);
+}
+lispval
+Lzerop()
+{
+       register lispval handy;
+
+       chkarg(1,"zerop");
+       handy = lbot->val;
+       switch(TYPE(handy)) {
+       case INT:
+               return(handy->i==0?tatom:nil);
+       case DOUB:
+               return(handy->r==0.0?tatom:nil);
+       }
+       return(nil);
+}
+lispval
+Lonep()
+{
+       register lispval handy; 
+       lispval Ladd();
+
+       handy = lbot->val;
+       switch(TYPE(handy)) {
+       case INT:
+               return(handy->i==1?tatom:nil);
+       case DOUB:
+               return(handy->r==1.0?tatom:nil);
+       case SDOT:
+               protect(inewint(0));
+               handy = Ladd();
+               if(TYPE(handy)!=INT || handy->i !=1)
+                       return(nil);
+               else
+                       return(tatom);
+       }
+       return(nil);
+}
+
+lispval
+cmpx(lssp)
+{
+       register struct argent *argp;
+       register struct argent *outarg;
+       register struct argent *onp = np;
+       Savestack(3);
+
+
+       argp = lbot + 1;
+       outarg = np;
+       while(argp < onp) {
+
+               np = outarg + 2;
+               lbot = outarg;
+               if(lssp)
+                       *outarg = argp[-1], outarg[1]  = *argp++;
+               else
+                       outarg[1]  = argp[-1], *outarg = *argp++;
+               lbot->val = Lsub();
+               np = lbot + 1;
+               if(Lnegp()==nil) 
+               {
+                   Restorestack();
+                   return(nil);
+               }
+       }
+       Restorestack();
+       return(tatom);
+}
+
+lispval
+Lgreaterp()
+{
+       register int typ;
+       /* do the easy cases first */
+       if(np-lbot == 2)
+       {   if((typ=TYPE(lbot->val)) == INT)
+           {    if((typ=TYPE(lbot[1].val)) == INT)
+                  return((lbot[0].val->i - lbot[1].val->i) > 0 ? tatom : nil);
+                else if(typ == DOUB)
+                 return((lbot[0].val->i - lbot[1].val->r) > 0.0 ? tatom : nil);
+           }
+           else if(typ == DOUB)
+           {    if((typ=TYPE(lbot[1].val)) == INT)
+                 return((lbot[0].val->r - lbot[1].val->i) > 0.0 ? tatom : nil);
+                else if(typ == DOUB)
+                 return((lbot[0].val->r - lbot[1].val->r) > 0.0 ? tatom : nil);
+           }
+       }
+                 
+       return(cmpx(FALSE));
+}
+
+lispval
+Llessp()
+{
+       register int typ;
+       /* do the easy cases first */
+       if(np-lbot == 2)
+       {   if((typ=TYPE(lbot->val)) == INT)
+           {    if((typ=TYPE(lbot[1].val)) == INT)
+                  return((lbot[0].val->i - lbot[1].val->i) < 0 ? tatom : nil);
+                else if(typ == DOUB)
+                 return((lbot[0].val->i - lbot[1].val->r) < 0.0 ? tatom : nil);
+           }
+           else if(typ == DOUB)
+           {    if((typ=TYPE(lbot[1].val)) == INT)
+                 return((lbot[0].val->r - lbot[1].val->i) < 0.0 ? tatom : nil);
+                else if(typ == DOUB)
+                 return((lbot[0].val->r - lbot[1].val->r) < 0.0 ? tatom : nil);
+           }
+       }
+                 
+       return(cmpx(TRUE));
+}
+
+lispval
+Ldiff()
+{
+       register lispval arg1,arg2; 
+       register handy = 0;
+
+
+       chkarg(2,"Ldiff");
+       arg1 = lbot->val;
+       arg2 = (lbot+1)->val;
+       if(TYPE(arg1)==INT && TYPE(arg2)==INT) {
+               handy=arg1->i - arg2->i;
+       }
+       else error("non-numeric argument",FALSE);
+       return(inewint(handy));
+}
+
+lispval
+Lmod()
+{
+       register lispval arg1,arg2;
+       lispval  handy;
+       struct sdot fake1, fake2;
+       fake2.CDR = 0;
+       fake1.CDR = 0;
+
+       chkarg(2,"mod");
+       handy = arg1 = lbot->val;
+       arg2 = (lbot+1)->val;
+       switch(TYPE(arg1)) {
+       case SDOT:
+               switch(TYPE(arg2)) {
+               case SDOT:                      /* both are already bignums */
+                       break;
+               case INT:                       /* convert arg2 to bignum   */
+                       fake2.I = arg2->i;
+                       arg2 =(lispval) &fake2;
+                       break;
+               default:
+                       error("non-numeric argument",FALSE);
+               }
+               break;
+       case INT:
+               switch(TYPE(arg2)) {
+               case SDOT:                      /* convert arg1 to bignum */
+                       fake1.I = arg1->i;
+                       arg1 =(lispval) &fake1;
+                       break;
+               case INT:                       /* both are fixnums       */
+                       return( inewint ((arg1->i) % (arg2->i)) );
+               default:
+                       error("non-numeric argument",FALSE);
+               }
+               break;
+       default:
+               error("non-numeric argument",FALSE);
+       }
+       if(TYPE((lbot+1)->val)==INT && lbot[1].val->i==0)
+               return(handy);
+       divbig(arg1,arg2,(lispval *)0,&handy);
+       if(handy==((lispval)&fake1))
+               handy = inewint(fake1.I);
+       if(handy==((lispval)&fake2))
+               handy = inewint(fake2.I);
+       return(handy);
+}
+lispval
+Ladd1()
+{
+       register lispval handy;
+       lispval Ladd();
+       Savestack(1); /* fixup entry mask */
+       chkarg(1,"add1");
+
+       /* simple test first */
+       if((TYPE(lbot->val) == INT) && (lbot->val->i < MaxINT))
+       {
+           Restorestack();
+           return(inewint(lbot->val->i + 1));
+       }
+       
+       handy = rdrint;
+       handy->i = 1;
+       protect(handy);
+       handy=Ladd();
+       Restorestack();
+       return(handy);
+
+}
+
+
+
+lispval
+Lsub1()
+{
+       register lispval handy;
+       lispval Ladd();
+       Savestack(1); /* fixup entry mask */
+       chkarg(1,"sub1");
+       
+       if((TYPE(lbot->val) == INT) && (lbot->val->i > MinINT))
+       {
+           Restorestack();
+           return(inewint(lbot->val->i - 1));
+       }
+
+       handy = rdrint;
+       handy->i = - 1;
+       protect(handy);
+       handy=Ladd();
+       Restorestack();
+       return(handy);
+}
+
+lispval
+Lminus()
+{
+       register lispval arg1, handy;
+       lispval subbig();
+
+       chkarg(1,"minus");
+       arg1 = lbot->val;
+       handy = nil;
+       switch(TYPE(arg1)) {
+       case INT:
+               handy= inewint(0 - arg1->i);
+               break;
+       case DOUB:
+               handy = newdoub();
+               handy->r = -arg1->r;
+               break;
+       case SDOT: { struct sdot dummyb;
+               handy = (lispval) &dummyb;
+               handy->s.I = 0;
+               handy->s.CDR = (lispval) 0;
+               handy = subbig(handy,arg1);
+               break; }
+
+       default:
+               error("non-numeric argument",FALSE);
+       }
+       return(handy);
+}
+
+lispval
+Lnegp()
+{
+       register lispval handy = np[-1].val, work;
+       register flag = 0;
+
+loop:
+       switch(TYPE(handy)) {
+       case INT:
+               if(handy->i < 0) flag = TRUE;
+               break;
+       case DOUB:
+               if(handy->r < 0) flag = TRUE;
+               break;
+       case SDOT:
+               for(work = handy;
+                   work->s.CDR!=(lispval) 0;
+                   work = work->s.CDR) {;}
+               if(work->s.I < 0) flag = TRUE;
+               break;
+       default:
+               handy = errorh1(Vermisc,
+                                 "minusp: Non-(int,real,bignum) arg: ",
+                                 nil,
+                                 TRUE,
+                                 0,
+                                 handy);
+               goto loop;
+       }
+       if(flag) return(tatom);
+       return(nil);
+}
+
+lispval
+Labsval()
+{
+       register lispval arg1;
+
+       chkarg(1,"absval");
+       arg1 = lbot->val;
+       if(Lnegp()!=nil) return(Lminus());
+
+       return(arg1);
+}
+
+/*
+ *
+ * (oblist)
+ *
+ * oblist returns a list of all symbols in the oblist
+ *
+ * written by jkf.
+ */
+lispval
+Loblist()
+{
+    int indx;
+    lispval headp, tailp ;
+    struct atom *symb ;
+    extern int hashtop;
+    Savestack(0);
+
+    headp = tailp = newdot(); /* allocate first DTPR */
+    protect(headp);            /*protect the list from garbage collection*/
+                               /*line added by kls                       */
+
+    for( indx=0 ; indx <= hashtop-1 ; indx++ ) /* though oblist */
+    {
+       for( symb = hasht[indx] ;
+            symb != (struct atom *) CNIL ;
+            symb = symb-> hshlnk)
+       {
+           if(TYPE(symb) != ATOM) 
+           {   printf(" non symbol in hasht[%d] = %x: ",indx,symb);
+               printr((lispval) symb,stdout);
+               printf(" \n");
+               fflush(stdout);
+           }
+           tailp->d.car = (lispval) symb  ; /* remember this atom */
+           tailp = tailp->d.cdr = newdot() ; /* link to next DTPR */
+       }
+    }
+
+    tailp->d.cdr = nil ; /* close the list unfortunately throwing away
+                         the last DTPR
+                         */
+    Restorestack();
+    return(headp);
+}
+
+/*
+ * Maclisp setsyntax function:
+ *    (setsyntax c s x)
+ * c represents character either by fixnum or atom
+ * s is the atom "macro" or the atom "splicing" (in which case x is the
+ * macro to be invoked); or nil (meaning don't change syntax of c); or
+ * (well thats enough for now) if s is a fixnum then we modify the bits
+ * for c in the readtable.
+ */
+
+lispval
+Lsetsyn()
+{
+       register lispval s, c;
+       register struct argent *mynp;
+       register index;
+       lispval x   /*  ,debugmode  */;
+       extern unsigned char *ctable;
+       extern lispval Istsrch();
+
+       switch(np-lbot) {
+       case 2:
+               x= nil;                 /* only 2 args given */
+       case 3:
+               x = lbot[2].val;        /* all three args given */
+               break;
+       default:
+               argerr("setsyntax");
+       }
+       s = Vreadtable->a.clb;
+       chkrtab(s);
+       /* debugging code 
+       debugmode = Istsrch(matom("debugging"))->d.cdr->d.cdr->d.cdr;
+       if(debugmode)  printf("Readtable addr: %x\n",ctable);
+         end debugging code */
+       mynp = lbot;
+       c = (mynp++)->val;
+       s = (mynp++)->val;
+
+       switch(TYPE(c)) {
+       default:
+               error("neither fixnum, atom or string as char to setsyntax",FALSE);
+
+       case ATOM:
+               index = *(c->a.pname);
+               if((c->a.pname)[1])
+                   errorh1(Vermisc,"Only 1 char atoms to setsyntax",
+                        nil,FALSE,0,c);
+               break;
+
+       case INT:
+               index = c->i;
+               break;
+
+       case STRNG:
+               index = (int) *((char *) c);
+       }
+       switch(TYPE(s)) {
+       case ATOM:
+               if(s==splice || s==macro) {
+                   if(s==splice)
+                           ctable[index] = VSPL;
+                   else if(s==macro)
+                           ctable[index] = VMAC;
+                   if(TYPE(c)!=ATOM) {
+                           strbuf[0] = index;
+                           strbuf[1] = 0;
+                           c = (getatom(TRUE));
+                   }
+                   Iputprop(c,x,lastrtab);
+                   return(tatom);
+               }
+
+               /* ... fall into */
+       default:  errorh1(Vermisc,"int:setsyntax : illegal second argument ",
+                               nil,FALSE,0,s);
+               /* not reached */
+               
+       case INT:
+               switch(synclass(s->i)) {
+               case CESC: Xesc = (char) index; break;
+               case CDQ: Xdqc = (char) index; break;
+               case CSD: Xsdc = (char) index;  /* string */
+               }
+
+               if(synclass(ctable[index])==CESC   /* if we changed the current esc */
+                 && (synclass(s->i)!=CESC)          /* to something else, pick current */
+                 && Xesc == (char) index) {
+                       ctable[index] = s->i;
+                       rpltab(CESC,&Xesc);
+               }
+               else if(synclass(ctable[index])==CDQ   /*  likewise for double quote */
+                      && synclass(s->i) != CDQ
+                      && Xdqc == (char) index)  {
+                       ctable[index] = s->i;
+                       rpltab(CDQ,&Xdqc);
+               }
+               else if(synclass(ctable[index]) == CSD  /* and for string delimiter */
+                       && synclass(s->i) != CSD
+                       && Xsdc == (char) index) {
+                        ctable[index] = s->i;
+                        rpltab(CSD,&Xsdc);
+               }
+               else ctable[index] = s->i;
+
+               break;
+
+       }
+       return(tatom);
+}
+
+/*
+ * this aux function is used by setsyntax to determine the new current
+ * escape or double quote character.  It scans the character table for
+ * the first character with the given class (either VESC or VDQ) and
+ * puts that character in Xesc or Xdqc (whichever is pointed to by
+ * addr).
+ */
+rpltab(cclass,addr)
+char cclass;
+unsigned char *addr;
+{
+       register int i;
+       extern unsigned char *ctable;
+       for(i=0; i<=127 && synclass(ctable[i]) != cclass; i++);
+       if(i<=127) *addr = (unsigned char) i;
+       else *addr = '\0';
+}
+
+
+/*
+ * int:getsyntax from lisp.
+ * returns the fixnum syntax code from the readtable for the given character.
+ * to be used by the lisp-code function getsyntax, not to be used by 
+ * joe user.
+ */
+lispval
+Lgetsyntax()
+{
+    register char *name;
+    int number, typ;
+    lispval handy;
+    
+    chkarg(1,"int:getsyntax");
+    handy = lbot[0].val;
+    while (1)
+    {
+       if((typ = TYPE(handy)) == ATOM)
+       {
+           name = handy->a.pname;
+       }
+       else if (typ == STRNG)
+       {
+           name = (char *)handy;
+       }
+       else if(typ == INT)
+       {
+           number = handy->i;
+           break;
+       }
+       else {
+           handy =
+             errorh1(Vermisc,"int:getsyntax : bad character ",
+                       nil,TRUE,0,handy);
+           continue;   /* start at the top */
+       }
+       /* figure out the number of the first byte */
+       number = (int) name[0];
+       if(name[1] != '\0')
+       {
+           handy = errorh1(Vermisc,
+           "int:getsyntax : only single character allowed ",
+           nil,TRUE,0,handy);
+       }
+       else break;
+    }
+    /* see if number is within range */
+    if(number < 0 || number > 255)
+       errorh1(Vermisc,"int:getsyntax : character number out of range ",nil,
+               FALSE,0,inewint(number));
+    chkrtab(Vreadtable->a.clb);  /* make sure readtable is correct */
+    return(inewint(ctable[number]));
+}
+    
+    
+       
+    
+lispval
+Lzapline()
+{
+       register FILE *port;
+       extern FILE * rdrport;
+
+       port = rdrport;
+       while (!feof(port) && (getc(port)!='\n') );
+       return(nil);
+}
diff --git a/usr/src/ucb/lisp/franz/lam5.c b/usr/src/ucb/lisp/franz/lam5.c
new file mode 100644 (file)
index 0000000..fdf7801
--- /dev/null
@@ -0,0 +1,579 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam5.c,v 1.5 83/09/12 14:14:15 sklower Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:49:06 1983 by jkf]-
+ *     lam5.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include "chkrtab.h"
+#include <ctype.h>
+char *strcpy(), *sprintf();
+
+/*===========================================
+-
+-      explode functions: aexplode , aexplodec, aexploden
+- The following function partially implement the explode functions for atoms.
+-  The full explode functions are written in lisp and call these for atom args.
+-
+-===========================================*/
+
+#include "chars.h"
+lispval
+Lexpldx(kind,slashify)
+int kind, slashify;    /* kind = 0 => explode to characters 
+                               = 1 => explode to fixnums (aexploden)
+                          slashify = 0 => do not quote bizarre characters
+                                   = 1 => quote bizarre characters
+                       */
+{
+       int typ, i;
+       char ch, *strb, strbb[BUFSIZ], *alloca();  /* temporary string buffer */
+       register lispval last, handy;
+       extern int uctolc;
+       register char *cp;
+#ifdef SPISFP
+       Keepxs();
+#endif
+       Savestack(3); /* kludge register save mask */
+
+       chkarg(1,"expldx");
+
+       handy = Vreadtable->a.clb;
+       chkrtab(handy);
+       handy = lbot->val;
+       *strbuf = 0;
+       typ=TYPE(handy);        /* we only work for a few types */
+
+
+       /* put the characters to return in the string buffer strb */
+
+       switch(typ) {
+       case STRNG:
+               if(slashify && !Xsdc)
+                   errorh1(Vermisc,"Can't explode without string delimiter",nil
+                                         ,FALSE,0,handy);
+               
+               strb = strbb;
+               if(slashify) *strb++ = Xsdc;
+               /* copy string into buffer, escape only occurances of the 
+                  double quoting character if in slashify mode
+               */
+               for(cp = (char *) handy; *cp; cp++)
+               {
+                 if(slashify &&
+                    (*cp == Xsdc || synclass(ctable[*cp])==CESC))
+                        *strb++ = Xesc;
+                 *strb++ = *cp;
+               }
+               if(slashify) *strb++ = Xsdc;
+               *strb = NULL_CHAR ;
+               strb = strbb;
+               break;
+
+       case ATOM:
+               strb = handy->a.pname;
+               if(slashify && (strb[0]==0)) {
+                       strb = strbb;
+                       strbb[0] = Xdqc;
+                       strbb[1] = Xdqc;
+                       strbb[2] = 0;
+               } else
+       /*common:*/
+               if(slashify != 0)
+               {
+                       char *out = strbb;
+                       unsigned char code;
+
+                       cp = strb;
+                       strb = strbb;
+                       code = ctable[(*cp)&0177];
+                       switch(synclass(code)) {
+                       case CNUM:
+                               *out++ = Xesc;
+                               break;
+                       case CCHAR:
+                               if(uctolc && isupper((*cp)&0177)) {
+                                   *out++ = Xesc;
+                               }
+                               break;
+                       default:
+                           switch(code&QUTMASK) {
+                           case QWNUNIQ:
+                                   if (cp[1]==0) *out++ = Xesc;
+                                   break;
+                           case QALWAYS:
+                           case QWNFRST:
+                                   *out++ = Xesc;
+                           }
+                       }
+                       *out++ = *cp++;
+                       for(; *cp; cp++)
+                       {
+                               if(((ctable[*cp]&QUTMASK)==QALWAYS) ||
+                                  (uctolc && isupper(*cp)))
+                                       *out++ = Xesc;
+                               *out++ = *cp;
+                       }
+                       *out = 0;
+               }
+               break;
+                               
+       case INT:
+               strb = strbb;
+               sprintf(strb, "%d", lbot->val->i);
+               break;
+       case DOUB:
+               strb = strbb;
+               lfltpr(strb, lbot->val->r);
+               break;
+       case SDOT:
+       {
+               struct _iobuf _strbuf;
+               int count;
+               for((handy = lbot->val), count = 12;
+                   handy->s.CDR!=(lispval) 0;
+                   (handy = handy->s.CDR), count += 12);
+               strb = alloca(count);
+
+               _strbuf._flag = _IOWRT+_IOSTRG;
+               _strbuf._ptr = strb;
+               _strbuf._cnt = count;
+               pbignum(lbot->val,&_strbuf);
+               putc(0,&_strbuf);
+               break;
+       }
+       default:
+                       errorh1(Vermisc,"EXPLODE ARG MUST BE STRING, SYMBOL, FIXNUM, OR FLONUM",nil,FALSE,0,handy);
+                       Restorestack();
+                       Freexs();
+                       return(nil);
+               }
+
+
+       if( strb[0] != NULL_CHAR )      /* if there is something to do */
+       {
+           lispval prev;
+
+           protect(handy = last = newdot()); 
+           strbuf[1] = NULL_CHAR ;     /* set up for getatom */
+           atmlen = 2;
+
+           for(i=0; ch = strb[i++]; ) {
+               switch(kind) {
+
+                 case 0: strbuf[0] = hash = ch;   /* character explode */
+                         last->d.car = (lispval) getatom(TRUE); /* look in oblist */
+                         break;
+
+                 case 1: 
+                         last->d.car = inewint(ch);
+                         break;
+               }
+
+               /* advance pointers */
+               prev = last;
+               last->d.cdr = newdot();
+               last = last->d.cdr;
+           }
+
+           /* end list with a nil pointer */
+           prev->d.cdr = nil;
+           Freexs();
+           Restorestack();
+           return(handy);
+       }
+       Freexs();
+       Restorestack();
+       return(nil);    /* return nil if no characters */
+}
+
+/*===========================
+-
+- (aexplodec 'atm) returns (a t m)
+- (aexplodec 234) returns (\2 \3 \4)
+-===========================*/
+
+lispval
+Lexpldc()
+{ return(Lexpldx(0,0)); }
+
+
+/*===========================
+-
+- (aexploden 'abc) returns (65 66 67)
+- (aexploden 123)  returns (49 50 51)
+-=============================*/
+
+
+lispval
+Lexpldn()
+{ return(Lexpldx(1,0)); }
+
+/*===========================
+-
+- (aexplode "123")  returns (\\ \1 \2 \3);
+- (aexplode 123)  returns (\1 \2 \3);
+-=============================*/
+
+lispval
+Lexplda()
+{ return(Lexpldx(0,1)); }
+
+/*
+ * (argv) returns how many arguments where on the command line which invoked
+ * lisp; (argv i) returns the i'th argument made into an atom;
+ */
+
+lispval
+Largv()
+{
+       register lispval handy;
+       extern int Xargc;
+       extern char **Xargv;
+
+       if(lbot-np==0)handy = nil;
+       else handy = lbot->val;
+       
+       if(TYPE(handy)==INT && handy->i>=0 && handy->i<Xargc) {
+               strcpy(strbuf,Xargv[handy->i]);
+               return(getatom(FALSE));
+       } else { 
+               return(inewint(Xargc));
+       }
+}
+/*
+ * (chdir <atom>) executes a chdir command
+ * if successful, return t otherwise returns nil
+ */
+lispval Lchdir(){
+       register char *filenm;
+
+       chkarg(1,"chdir");
+       filenm = (char *) verify(lbot->val,"chdir - non symbol or string arg");
+       if(chdir(filenm)>=0)
+               return(tatom);
+       else
+               return(nil);
+}
+
+/* ==========================================================
+-
+-      ascii   - convert from number to ascii character
+-
+- form:(ascii number)
+-
+-      the number is checked so that it is in the range 0-255
+- then it is made a character and returned
+- =========================================================*/
+
+lispval
+Lascii() 
+{
+       register lispval handy;
+
+       handy = lbot->val;              /* get argument */
+
+       if(TYPE(handy) != INT)          /* insure that it is an integer */
+       {       error("argument not an integer",FALSE);
+               return(nil);
+       }
+
+       if(handy->i < 0 || handy->i > 0377)     /* insure that it is in range*/
+       {       error("argument is out of ascii range",FALSE);
+               return(nil);
+       }
+
+       strbuf[0] = handy->i ;  /* ok value, make into a char */
+       strbuf[1] = NULL_CHAR;
+
+       /* lookup and possibly intern the atom given in strbuf */
+
+       return( (lispval) getatom(TRUE) );
+}
+
+/*
+ *  boole - maclisp bitwise boolean function
+ *  (boole k x y) where k determines which of 16 possible bitwise 
+ *  truth tables may be applied.  Common values are 1 (and) 6 (xor) 7 (or)
+ *  the result is mapped over each pair of bits on input
+ */
+lispval
+Lboole(){
+       register x, y;
+       register struct argent *mynp;
+       int k;
+
+       if(np - lbot < 3)
+               error("Boole demands at least 3 args",FALSE);
+       mynp = lbot+AD;
+       k = mynp->val->i & 15;
+       x = (mynp+1)->val->i;
+       for(mynp += 2; mynp < np; mynp++) {
+               y = mynp->val->i;
+               switch(k) {
+
+               case 0: x = 0;
+                       break;
+               case 1: x = x & y;
+                       break;
+               case 2: x = y & ~x;
+                       break;
+               case 3: x = y;
+                       break;
+               case 4: x = x & ~y;
+                       break;
+               /* case 5:      x = x; break; */
+               case 6: x = x ^ y;
+                       break;
+               case 7: x = x | y;
+                       break;
+               case 8: x = ~(x | y);
+                       break;
+               case 9: x = ~(x ^ y);
+                       break;
+               case 10: x = ~x;
+                       break;
+               case 11: x = ~x | y;
+                       break;
+               case 12: x = ~y;
+                       break;
+               case 13: x = x | ~y;
+                       break;
+               case 14: x = ~x | ~y;
+                       break;
+               case 15: x = -1;
+               }
+       }
+       return(inewint(x));
+}
+lispval
+Lfact()
+{
+       register lispval result, handy;
+       register itemp;
+       Savestack(3); /* fixup entry mask */
+
+       result = lbot->val;
+       if(TYPE(result)!=INT) error("Factorial of Non-fixnum.  If you want me\
+to calculate fact of > 2^30 We will be here till doomsday!.",FALSE);
+       itemp = result->i;
+       protect(result = newsdot());
+       result->s.CDR=(lispval)0;
+       result->i = 1;
+       for(; itemp > 1; itemp--)
+               dmlad(result,(long)itemp,0L);
+       if(result->s.CDR) 
+       {
+           Restorestack();
+           return(result);
+       }
+       handy = inewint(result->s.I);
+       pruneb(result);
+       Restorestack();
+       return(handy);
+}
+/*
+ * fix -- maclisp floating to fixnum conversion
+ * for the moment, mereley convert floats to ints.
+ * eventual convert to bignum if too big to fit.
+ */
+ lispval Lfix() 
+ {
+       register lispval handy;
+       double floor();
+
+       chkarg(1,"fix");
+       handy = lbot->val;
+       switch(TYPE(handy)) {
+       default:
+               error("innaproriate arg to fix.",FALSE);
+       case INT:
+       case SDOT:
+               return(handy);
+       case DOUB:
+               return(inewint((int)floor(handy->r)));
+       }
+}
+/*
+ * (frexp <real no>)
+ * returns a dotted pair (<exponent>. <bignum>)
+ * such that bignum is 56 bits long, and if you think of the binary
+ * point occuring after the high order bit, <real no> = 2^<exp> * <bignum>
+ *
+ * myfrexp is an assembly language routine found in bigmath.s to do exactly
+ * what is necessary to accomplish this.
+ * this routine is horribly vax specific.
+ *
+ * Lfix should probably be rewritten to take advantage of myfrexp
+ */
+lispval
+Lfrexp()
+{
+       register lispval handy, result;
+       int exp, hi, lo;
+
+       Savestack(2);
+       chkarg(1,"frexp");
+
+       myfrexp(lbot->val->r, &exp, &hi, &lo);
+       if(lo < 0) {
+               /* normalize for bignum */
+               lo &= ~ 0xC0000000;
+               hi += 1;
+       }
+       result = handy = newdot(); 
+       protect(handy);
+       handy->d.car = inewint(exp);
+       if(hi==0&&lo==0) {
+               handy->d.cdr = inewint(0);
+       } else {
+               handy = handy->d.cdr = newsdot();
+               handy->s.I = lo;
+               handy = handy->s.CDR = newdot();
+               handy->s.I = hi;
+               handy->s.CDR = 0;
+       }
+       np--;
+       Restorestack();
+       return(result);
+}
+
+#define SIGFPE 8
+#define B 1073741824.0
+static double table[] = { 1.0, B, B*B, B*B*B, B*B*B*B, 0.0};
+
+lispval
+Lfloat()
+{
+       register lispval handy,result;
+       register double sum = 0;
+       register int count;
+       chkarg(1,"float");
+       handy = lbot->val;
+       switch(TYPE(handy))
+       {
+         case DOUB: return(handy);
+
+
+         case INT:  result = newdoub();
+                    result->r = (double) handy->i;
+                    return(result);
+         case SDOT: 
+         {
+               for(handy = lbot->val, count = 0;
+                   count < 5;
+                   count++, handy = handy->s.CDR) {
+                       sum += handy->s.I * table[count];
+                       if(handy->s.CDR==(lispval)0) goto done;
+               }
+               kill(getpid(),SIGFPE);
+       done:
+               result = newdoub();
+               result->r = sum;
+               return(result);
+       }
+         default: errorh1(Vermisc,"Bad argument to float",nil,FALSE,0,handy);
+         /* NOTREACHED */
+       }
+}
+double
+Ifloat(handy)
+register lispval handy;
+{
+       register double sum = 0.0; register int count=0;
+       for(; count < 5; count++, handy = handy->s.CDR) {
+               sum += handy->s.I * table[count];
+               if(handy->s.CDR==(lispval)0) goto done;
+       }
+       kill(getpid(),SIGFPE);
+       done:
+       return(sum);
+}
+
+/* Lbreak ***************************************************************/
+/* If first argument is not nil, this is evaluated and printed.  Then  */
+/* error is called with the "breaking" message.                                */
+lispval Lbreak() {
+
+       if (np > lbot) {
+               printr(lbot->val,poport);
+               dmpport(poport);
+       }
+       return(error("",TRUE));
+}
+
+
+lispval
+LDivide() {
+       register lispval result, work;
+       register struct argent *mynp;
+       lispval quo, rem, arg1, arg2; struct sdot dummy, dum2;
+       Savestack(3);
+
+       chkarg(2,"Divide");
+       mynp = lbot;
+       work = mynp++->val;
+       switch(TYPE(work)) {
+       case INT:
+               arg1 = (lispval) &dummy;
+               dummy.I = work->i;
+               dummy.CDR = (lispval) 0;
+               break;
+       case SDOT:
+               arg1 = work;
+               break;
+       urk:
+       default:
+               error("First arg to divide neither a bignum nor int.",FALSE);
+       }
+       work = mynp->val;
+       switch(TYPE(work)) {
+       case INT:
+               arg2 = (lispval) &dum2;
+               dum2.I = work->i;
+               dum2.CDR = (lispval) 0;
+               break;
+       case SDOT:
+               arg2 = work;
+               break;
+       default:
+               goto urk;
+       }
+       divbig(arg1,arg2, &quo, &rem);
+       protect(quo);
+       if(rem==((lispval)&dummy))
+               rem = inewint(dummy.I);
+       protect(rem);
+       protect(result = work = newdot());
+       work->d.car = quo;
+       (work->d.cdr = newdot())->d.car = rem;
+       Restorestack();
+       return(result);
+}
+
+lispval LEmuldiv(){
+       register struct argent * mynp = lbot+AD;
+       register lispval work, result;
+       int quo, rem;
+       Savestack(3); /* fix register mask */
+
+       /* (Emuldiv mul1 mult2 add quo) => 
+               temp = mul1 + mul2 + sext(add);
+               result = (list temp/quo temp%quo);
+               to mix C and lisp a bit */
+
+       Imuldiv(mynp[0].val->i, mynp[1].val->i, mynp[2].val->i,
+               mynp[3].val->i, &quo, &rem);
+       protect(result=newdot());
+       (result->d.car=inewint(quo));
+       work = result->d.cdr = newdot();
+       (work->d.car=inewint(rem));
+       Restorestack();
+       return(result);
+}
diff --git a/usr/src/ucb/lisp/franz/lam6.c b/usr/src/ucb/lisp/franz/lam6.c
new file mode 100644 (file)
index 0000000..3e9defb
--- /dev/null
@@ -0,0 +1,577 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam6.c,v 1.5 83/09/12 14:16:37 sklower Exp $";
+#endif
+
+/*                                     -[Sun Sep  4 08:56:19 1983 by jkf]-
+ *     lam6.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include "frame.h"
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/times.h>
+#include "chkrtab.h"
+#include "chars.h"
+
+FILE *
+mkstFI(base,count,flag)
+char *base;
+char flag;
+{
+       register FILE *p = stderr;
+
+       /* find free file descriptor */
+       for( ;(p < &_iob[_NFILE]) && p->_flag&(_IOREAD|_IOWRT);p++);
+       if(p >= &_iob[_NFILE])
+           error("Too many open files to do readlist",FALSE);
+       p->_flag = _IOSTRG | flag;
+       p->_cnt = count;
+       p->_base = base;
+       p->_ptr = base;
+       p->_file = -1;
+       return(p);
+}
+
+lispval
+Lreadli()
+{
+       register lispval work, handy;
+       register FILE *p;
+       register char *string; char *alloca();
+       lispval Lread();
+       int count;
+       pbuf pb;
+#ifdef SPISFP
+       Keepxs();
+#endif
+       Savestack(4);
+
+       if(lbot->val==nil) {            /*effectively, return(matom(""));*/
+               strbuf[0] = 0;
+               return(getatom(FALSE));
+       }
+       chkarg(1,"readlist");
+       count = 1;
+
+       /* compute length of list */
+       for(work = lbot->val; TYPE(work)==DTPR; work=work->d.cdr)
+               count++;
+       string = alloca(count);
+       p = mkstFI(string, count - 1, _IOREAD);
+       for(work = lbot->val; TYPE(work)==DTPR; work=work->d.cdr) {
+               handy = work->d.car;
+               switch(TYPE(handy)) {
+               case SDOT:
+               case INT:
+                       *string++=handy->i;
+                       break;
+               case ATOM:
+                       *string++ = *(handy->a.pname);
+                       break;
+               case STRNG:
+                       *string++ = *(char *)handy;
+                       break;
+               default:
+                       frstFI(p);
+                       error("Non atom or int to readlist",FALSE);
+               }
+       }
+       *string = 0;
+       errp = Pushframe(F_CATCH,Veruwpt,nil);  /* must unwind protect
+                                                  so can deallocate p
+                                                */
+       switch(retval) { lispval Lctcherr();
+       case C_THROW:
+                       /* an error has occured and we are given a chance
+                          to unwind before the control goes higher
+                          lispretval contains the error descriptor in
+                          it's cdr
+                        */
+                     frstFI(p);        /* free port */
+                     errp = Popframe();
+                     Freexs();
+                     lbot = np;
+                     protect(lispretval->d.cdr); /* error descriptor */
+                     return(Lctcherr());       /* do a I-do-throw */
+                     
+       case C_INITIAL: 
+                       lbot = np;
+                       protect(P(p));
+                       work = Lread();  /* error  could occur here */
+                       Freexs();
+                       frstFI(p);      /* whew.. no errors */
+                       errp = Popframe();      /* remove unwind-protect */
+                       Restorestack();
+                       return(work);
+       }
+       /* NOTREACHED */
+}
+frstFI(p)
+register FILE *p;
+{
+       p->_flag=0;
+       p->_base=0;
+       p->_cnt = 0;
+       p->_ptr = 0;
+       p->_file = 0;
+}
+
+lispval
+Lgetenv()
+{
+       char *getenv(), *strcpy();
+       char *res;
+       chkarg(1,"getenv");
+       
+
+       if((TYPE(lbot->val))!=ATOM)
+               error("argument to getenv must be atom",FALSE);
+
+       res = getenv(lbot->val->a.pname);
+       if(res) strcpy(strbuf,res);
+       else strbuf[0] = '\0';
+       return(getatom(FALSE));
+}
+
+lispval
+Lboundp()
+{
+       register lispval result, handy;
+
+       chkarg(1,"boundp");
+
+       if((TYPE(lbot->val))!=ATOM)
+               error("argument to boundp must be symbol",FALSE);
+       if( (handy = lbot->val)->a.clb==CNIL)
+               result = nil;
+       else
+               (result = newdot())->d.cdr = handy->a.clb;
+       return(result);
+}
+
+
+lispval
+Lplist()
+{      
+       register lispval atm;
+       /* get property list of an atom or disembodied property list */
+
+       chkarg(1,"plist");
+       atm = lbot->val;
+       switch(TYPE(atm)) {
+       case ATOM:
+       case DTPR:
+               break;
+       default:
+               error("Only Atoms and disembodied property lists allowed for plist",FALSE);
+       }
+       if(atm==nil) return(nilplist);
+       return(atm->a.plist);
+}
+
+
+lispval
+Lsetpli()
+{      /* set the property list of the given atom to the given list */
+       register lispval atm, vall;
+
+       chkarg(2,"setplist");
+       atm = lbot->val;
+       if (TYPE(atm) != ATOM) 
+          error("setplist: First argument must be an symbol",FALSE);
+       vall = (np-1)->val;
+       if (TYPE(vall)!= DTPR && vall !=nil)
+           error("setplist: Second argument must be a list",FALSE);
+       if (atm==nil)
+               nilplist = vall;
+       else
+               atm->a.plist = vall;
+       return(vall);
+}
+
+lispval
+Lsignal()
+{
+       register lispval handy, old, routine;
+       int i;
+       int siginth();
+
+       switch(np-lbot) {
+
+       case 1: routine = nil;          /* second arg defaults to nil */
+               break;
+
+       case 2: routine = lbot[1].val;
+               break;                  /* both args given              */
+
+       default: argerr("signal");
+       }
+
+       handy = lbot->val;
+       if(TYPE(handy)!=INT)
+               error("First arg to signal must be an int",FALSE);
+       i = handy->i & 15;
+
+       if(TYPE(routine)!=ATOM)
+               error("Second arg to signal must be an atom",FALSE);
+       old = sigacts[i];
+
+       if(old==0) old = nil;
+
+       if(routine==nil)
+               sigacts[i]=((lispval) 0);
+       else
+               sigacts[i]=routine;
+       if(routine == nil)
+           signal(i,SIG_IGN);  /* ignore this signals */
+       else if (old == nil)
+           signal(i,siginth);  /* look for this signal */
+       if(i == SIGINT) sigintcnt = 0; /* clear memory */
+       return(old);
+}
+
+lispval
+Lassq()
+{
+       register lispval work, handy;
+
+       chkarg(2,"assq");
+
+       for(work = lbot[1].val, handy = lbot[0].val; 
+           (work->d.car->d.car != handy) && (work != nil);
+           work = work->d.cdr);
+       return(work->d.car);
+}
+
+lispval
+Lkilcopy()
+{
+       if(fork()==0) {
+               abort();
+       }
+}
+
+lispval
+Larg()
+{
+       register lispval handy; register offset, count;
+
+       handy = lexpr_atom->a.clb;
+       if(handy==CNIL || TYPE(handy)!=DTPR)
+               error("Arg: not in context of Lexpr.",FALSE);
+       count = ((long *)handy->d.cdr) -1 - (long *)handy->d.car;
+       if(np==lbot || lbot->val==nil)
+               return(inewint(count+1));
+       if(TYPE(lbot->val)!=INT || (offset = lbot->val->i - 1) > count || offset < 0 )
+               error("Out of bounds: arg to \"Arg\"",FALSE);
+       return( ((struct argent *)handy->d.car)[offset].val);
+}
+
+lispval
+Lsetarg()
+{
+       register lispval handy, work;
+       register limit, index;
+
+       chkarg(2,"setarg");
+       handy = lexpr_atom->a.clb;
+       if(handy==CNIL || TYPE(handy)!=DTPR)
+               error("Arg: not in context of Lexpr.",FALSE);
+       limit = ((long *)handy->d.cdr) - 1 -  (long *)(work = handy->d.car);
+       handy = lbot->val;
+       if(TYPE(handy)!=INT)
+               error("setarg: first argument not integer",FALSE);
+       if((index = handy->i - 1) < 0 || index > limit)
+               error("setarg: index out of range",FALSE);
+       return(((struct argent *) work)[index].val = lbot[1].val);
+}
+
+lispval
+Lptime(){
+       extern int gctime;
+       int lgctime = gctime;
+       struct tms current;
+       register lispval result, handy;
+       Savestack(2);
+
+       times(&current);
+       result = newdot();
+       handy = result;
+       protect(result);
+       result->d.cdr = newdot();
+       result->d.car = inewint(current.tms_utime);
+       handy = result->d.cdr;
+       handy->d.car = inewint(lgctime);
+       handy->d.cdr = nil;
+       if(gctime==0)
+               gctime = 1;
+       Restorestack();
+       return(result);
+}
+
+/* (err-with-message message [value])
+   'message' is the error message to print.
+   'value' is the value to return from the errset (if present).
+       it defaults to nil.
+    The message may not be printed if there is an (errset ... nil)
+    pending.
+ */
+
+lispval Lerr()
+{
+       lispval errorh();
+       lispval valret = nil;
+       char *mesg;
+       
+
+       switch(np-lbot) {
+        case 2: valret = lbot[1].val;  /* return non nil */
+        case 1: mesg = (char *)verify(lbot[0].val,
+                                 "err-with-message: non atom or string arg");
+                break;
+        default: argerr("err-with-message");
+       }
+       
+       return(errorh(Vererr,mesg,valret,FALSE,1));
+}
+
+/*
+ *  (tyi ['p_port ['g_eofval]])
+ * normally -1 is return on eof, but g_eofval will be returned if given.
+ */
+lispval
+Ltyi()
+{
+       register FILE *port;
+       register lispval handy;
+       lispval eofval;
+       int val;        /* really char but getc returns int on eof */
+       int eofvalgiven;
+
+       handy = nil;   /* default port */
+       eofvalgiven = FALSE;  /* assume no eof value given */
+       switch(np-lbot)
+       {
+           case 2:  eofval = lbot[1].val;
+                    eofvalgiven = TRUE;
+           case 1:  handy = lbot[0].val;       /* port to read */
+           case 0: 
+                    break;
+           default: argerr("tyi");
+       }
+
+       port = okport(handy,okport(Vpiport->a.clb,stdin));
+
+
+       fflush(stdout);         /* flush any pending output characters */
+       val = getc(port);
+       if(val==EOF)
+       {
+               clearerr(port);
+               if(sigintcnt > 0) sigcall(SIGINT);  /* eof might mean int */
+               if(eofvalgiven) return(eofval);
+               else return(inewint(-1));
+       }
+       return(inewint(val));
+}
+
+/* Untyi (added by DNC Feb. '80) - (untyi number port) puts the
+   character with ascii code number in the front of the input buffer of
+   port.  Note that this buffer is limited to 1 character.  That buffer is
+   also written by tyipeek, so a peek followed by an untyi will result in
+   the loss of the peeked char.
+ */
+   
+lispval
+Luntyi()
+{
+
+    lispval port,ch;
+
+    port = nil;
+
+    switch(np-lbot) {
+       case 2: port = lbot[1].val;
+       case 1: ch = lbot[0].val;
+               break;
+       default:
+               argerr("untyi");
+    }
+
+    if(TYPE(ch) != INT) {
+       errorh1(Vermisc, "untyi: expects fixnum character ",
+                               nil,FALSE,0,ch);
+    }  
+
+    ungetc((int) ch->i,okport(port,okport(Vpiport->a.clb,stdin)));
+    return(ch);
+}
+
+lispval
+Ltyipeek()
+{
+       register FILE *port;
+       register lispval handy;
+       int val;
+
+       switch(np-lbot)
+       {
+           case 0:  handy = nil;       /* default port */
+                    break;
+           case 1:  handy = lbot->val;
+                    break;
+           default: argerr("tyipeek");
+       }
+
+       port = okport(handy,okport(Vpiport->a.clb,stdin));
+
+       fflush(stdout);         /* flush any pending output characters */
+       val = getc(port);
+       if(val==EOF)
+               clearerr(port);
+       ungetc(val,port);
+       return(inewint(val));
+}
+
+lispval
+Ltyo()
+{
+       register FILE *port;
+       register lispval handy, where;
+       char val;
+
+       switch(np-lbot)
+       {
+           case 1:  where = nil;       /* default port */
+                    break;
+           case 2:  where = lbot[1].val;
+                    break;
+           default: argerr("tyo");
+       }
+
+       handy = lbot->val;
+       if(TYPE(handy)!=INT)
+               error("Tyo demands number for 1st arg",FALSE);
+       val = handy->i;
+
+       port = (FILE *) okport(where,okport(Vpoport->a.clb,stdout));
+       putc(val,port);
+       return(handy);
+}
+
+lispval
+Imkrtab(current)
+{
+       extern struct rtab {
+               unsigned char ctable[132];
+       } initread;
+       register lispval handy; extern lispval lastrtab;
+
+       static int cycle = 0;
+       static char *nextfree;
+       Savestack(3);
+       
+       if((cycle++)%3==0) {
+               nextfree = (char *) csegment(STRNG,1,FALSE);
+               mrtabspace = (lispval) nextfree;
+               /* need to protect partially allocated read tables
+                  from garbage collection. */
+       }
+       handy = newarray();
+       protect(handy);
+       
+       handy->ar.data = nextfree;
+       if(current == 0)
+               *(struct rtab *)nextfree = initread;
+       else
+       {
+               register index = 0; register char *cp = nextfree;
+               lispval c;
+
+               *(struct rtab *)cp = *(struct rtab *)ctable;
+               for(; index < 128; index++) {
+                   switch(synclass(cp[index])) {
+                   case CSPL: case CSSPL: case CMAC: case CSMAC:
+                   case CINF: case CSINF:
+                       strbuf[0] = index;
+                       strbuf[1] = 0;
+                       c = (getatom(TRUE));
+                       Iputprop(c,Iget(c,lastrtab),handy);
+                   }
+               }
+       }
+       handy->ar.delta = inewint(4);
+       handy->ar.length = inewint(sizeof(struct rtab)/sizeof(int));
+       handy->ar.accfun = handy->ar.aux  = nil;
+       nextfree += sizeof(struct rtab);
+       Restorestack();
+       return(handy);
+}
+
+/* makereadtable - arg : t or nil
+       returns a readtable, t means return a copy of the initial readtable
+
+                            nil means return a copy of the current readtable
+*/
+lispval
+Lmakertbl()
+{
+       lispval handy = Vreadtable->a.clb;
+       lispval value;
+       chkrtab(handy);
+
+       if(lbot==np) value = nil;
+       else if(TYPE(value=(lbot->val)) != ATOM) 
+               error("makereadtable: arg must be atom",FALSE);
+
+       if(value == nil) return(Imkrtab(1));
+       else return(Imkrtab(0));
+}
+
+lispval
+Lcpy1()
+{
+       register lispval handy = lbot->val, result = handy;
+
+top:
+       switch(TYPE(handy))
+       {
+       case INT:
+               result = inewint(handy->i);
+               break;
+       case VALUE:
+               (result = newval())->l = handy->l;
+               break;
+       case DOUB:
+               (result = newdoub())->r = handy->r;
+               break;
+       default:
+               lbot->val =
+                   errorh1(Vermisc,"Bad arg to cpy1",nil,TRUE,67,handy);
+               goto top;
+       }
+       return(result);
+}
+
+/* copyint* . This returns a copy of its integer argument.  The copy will
+ *      be a fresh integer cell, and will not point into the read only
+ *      small integer table.
+ */
+lispval
+Lcopyint()
+{
+       register lispval handy = lbot->val;
+       register lispval ret;
+
+       while (TYPE(handy) != INT)
+       { handy=errorh1(Vermisc,"copyint* : non integer arg",nil,TRUE,0,handy);}
+       (ret = newint())->i = handy->i;
+       return(ret);
+}
+
+
diff --git a/usr/src/ucb/lisp/franz/lam7.c b/usr/src/ucb/lisp/franz/lam7.c
new file mode 100644 (file)
index 0000000..2119501
--- /dev/null
@@ -0,0 +1,636 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam7.c,v 1.4 83/09/12 14:16:44 sklower Exp $";
+#endif
+
+/*                                     -[Fri Aug  5 12:51:31 1983 by jkf]-
+ *     lam7.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include <signal.h>
+
+char *sprintf();
+
+lispval
+Lfork() {
+       int pid;
+
+       chkarg(0,"fork");
+       if ((pid=fork())) {
+               return(inewint(pid));
+       } else
+               return(nil);
+}
+
+lispval
+Lwait()
+{
+       register lispval ret, temp;
+       int status = -1, pid;
+       Savestack(2);
+
+
+       chkarg(0,"wait");
+       pid = wait(&status);
+       ret = newdot();
+       protect(ret);
+       temp = inewint(pid);
+       ret->d.car = temp;
+       temp = inewint(status);
+       ret->d.cdr = temp;
+       Restorestack();
+       return(ret);
+}
+
+lispval
+Lpipe()
+{
+       register lispval ret, temp;
+       int pipes[2];
+       Savestack(2);
+
+       chkarg(0,"pipe");
+       pipes[0] = -1;
+       pipes[1] = -1;
+       pipe(pipes);
+       ret = newdot();
+       protect(ret);
+       temp = inewint(pipes[0]);
+       ret->d.car = temp;
+       temp = inewint(pipes[1]);
+       ret->d.cdr = temp;
+       Restorestack();
+       return(ret);
+}
+
+lispval
+Lfdopen()
+{
+       register lispval fd, type;
+       FILE *ptr;
+
+       chkarg(2,"fdopen");
+       type = (np-1)->val;
+       fd = lbot->val;
+       if( TYPE(fd)!=INT )
+               return(nil);
+       if ( (ptr=fdopen((int)fd->i, (char *)type->a.pname))==NULL)
+               return(nil);
+       return(P(ptr));
+}
+
+lispval
+Lexece()
+{
+       lispval fname, arglist, envlist, temp;
+       char *args[100], *envs[100], estrs[1024];
+       char *p, *cp, **argsp;
+
+       fname = nil;
+       arglist = nil;
+       envlist = nil;
+
+       switch(np-lbot) {
+       case 3: envlist = lbot[2].val;
+       case 2: arglist = lbot[1].val;
+       case 1: fname   = lbot[0].val;
+       case 0: break;
+       default:
+               argerr("exece");
+       }
+
+       while (TYPE(fname)!=ATOM)
+          fname = error("exece: non atom function name",TRUE);
+       while (TYPE(arglist)!=DTPR && arglist!=nil)
+               arglist = error("exece: non list arglist",TRUE);
+       for (argsp=args; arglist!=nil; arglist=arglist->d.cdr) {
+               temp = arglist->d.car;
+               if (TYPE(temp)!=ATOM)
+                       error("exece: non atom argument seen",FALSE);
+               *argsp++ = temp->a.pname;
+       }
+       *argsp = 0;
+       if (TYPE(envlist)!=DTPR && envlist!=nil)
+               return(nil);
+       for (argsp=envs,cp=estrs; envlist!=nil; envlist=envlist->d.cdr) {
+               temp = envlist->d.car;
+               if (TYPE(temp)!=DTPR || TYPE(temp->d.car)!=ATOM
+                 || TYPE(temp->d.cdr)!=ATOM)
+                    error("exece: Bad enviroment list",FALSE);
+               *argsp++ = cp;
+               for (p=temp->d.car->a.pname; (*cp++ = *p++);) ;
+               *(cp-1) = '=';
+               for (p=temp->d.cdr->a.pname; (*cp++ = *p++);) ;
+       }
+       *argsp = 0;
+       
+       return(inewint(execve(fname->a.pname, args, envs)));
+}
+
+/* Lprocess -
+ * C code to implement the *process function
+ * call:
+ *     (*process 'st_command ['s_readp ['s_writep]])
+ * where st_command is the command to execute
+ *   s_readp is non nil if you want a port to read from returned
+ *   s_writep is non nil if you want a port to write to returned
+ *   both flags default to nil
+ * *process returns
+ *    the exit status of the process if s_readp and s_writep not given
+ *     (in this case the parent waits for the child to finish)
+ *    a list of (readport writeport childpid) if one of s_readp or s_writep
+ *    is given.  If only s_readp is non nil, then writeport will be nil,
+ *    If only s_writep is non nil, then readport will be nil
+ */
+
+lispval
+Lprocess()
+{
+       int wflag , childsi , childso , child;
+       lispval handy;
+       char *command, *p;
+       int writep, readp;
+       int itemp;
+       int (*handler)(), (*signal())();
+       FILE *bufs[2],*obufs[2], *fpipe();
+       Savestack(0);
+
+       writep = readp = FALSE;
+       wflag = TRUE;
+       
+       switch(np-lbot) {
+       case 3:  if(lbot[2].val != nil) writep = TRUE;
+       case 2:  if(lbot[1].val != nil) readp = TRUE;
+                wflag = 0;
+       case 1:  command = (char *) verify(lbot[0].val,
+                                           "*process: non atom first arg");
+                break;
+       default:
+               argerr("*process");
+       }
+       
+       childsi = 0;
+       childso = 1;
+
+       /* if there will be communication between the processes,
+        * it will be through these pipes:
+        *  parent ->  bufs[1] ->  bufs[0] -> child    if writep
+        *  parent <- obufs[0] <- obufs[1] <- parent   if readp
+        */
+       if(writep) {
+           fpipe(bufs);
+           childsi = fileno(bufs[0]);
+       }
+       
+       if(readp) {
+               fpipe(obufs);
+               childso = fileno(obufs[1]);
+       }
+       
+       handler = signal(SIGINT,SIG_IGN);
+       if((child = vfork()) == 0 ) {
+               /* if we will wait for the child to finish
+                * and if the process had ignored interrupts before
+                * we were called, then leave them ignored, else
+                * set it back the the default (death)
+                */
+               if(wflag && handler != SIG_IGN)
+                       signal(2,SIG_DFL);
+                       
+               if(writep) {
+                       close(0);
+                       dup(childsi);
+               }
+               if (readp) {
+                       close(1);
+                       dup(childso);
+               }
+               if ((p = (char *)getenv("SHELL")) != (char *)0) {
+                       execlp(p , p, "-c",command,0);
+                       _exit(-1); /* if exec fails, signal problems*/
+               } else {
+                       execlp("csh", "csh", "-c",command,0);
+                       execlp("sh", "sh", "-c",command,0);
+                       _exit(-1); /* if exec fails, signal problems*/
+               }
+       }
+
+       /* close the duplicated file descriptors
+        * e.g. if writep is true then we've created two desriptors,
+        *  bufs[0] and bufs[1],  we will write to bufs[1] and the
+        *  child (who has a copy of our bufs[0]) will read from bufs[0]
+        *  We (the parent) close bufs[0] since we will not be reading
+        *  from it.
+        */
+       if(writep) fclose(bufs[0]);
+       if(readp) fclose(obufs[1]);
+
+       if(wflag && child!= -1) {
+               int status=0;
+               /* we await the death of the child */
+               while(wait(&status)!=child) {}
+               /* the child has died */
+               signal(2,handler);      /* restore the interrupt handler */
+               itemp = status >> 8;
+               Restorestack();
+               return(inewint(itemp)); /* return its status */
+       }
+       /* we are not waiting for the childs death
+        * build a list containing the write and read ports
+        */
+       protect(handy = newdot());
+       handy->d.cdr = newdot();
+       handy->d.cdr->d.cdr = newdot();
+       if(readp) {
+           handy->d.car = P(obufs[0]);
+           ioname[PN(obufs[0])] = (lispval) inewstr((char *) "from-process");
+       }
+       if(writep) {
+           handy->d.cdr->d.car = P(bufs[1]);
+           ioname[PN(bufs[1])] = (lispval) inewstr((char *) "to-process");
+       }
+       handy->d.cdr->d.cdr->d.car = (lispval) inewint(child);
+       signal(SIGINT,handler);
+       Restorestack();
+       return(handy);
+}
+
+extern int gensymcounter;
+
+lispval
+Lgensym()
+{
+       lispval arg;
+       char leader;
+
+       switch(np-lbot)
+       {
+           case 0: arg = nil;
+                   break;
+           case 1: arg = lbot->val;
+                   break;
+           default: argerr("gensym");
+       }
+       leader = 'g';
+       if (arg != nil && TYPE(arg)==ATOM)
+               leader = arg->a.pname[0];
+       sprintf(strbuf, "%c%05d", leader, gensymcounter++);
+       atmlen = 7;
+       return((lispval)newatom(0));
+}
+
+extern struct types {
+char   *next_free;
+int    space_left,
+       space,
+       type,
+       type_len;                       /*  note type_len is in units of int */
+lispval *items,
+       *pages,
+       *type_name;
+struct heads
+       *first;
+} atom_str ;
+
+lispval
+Lremprop()
+{
+       register struct argent *argp;
+       register lispval pptr, ind, opptr;
+       lispval atm;
+       int disemp = FALSE;
+
+       chkarg(2,"remprop");
+       argp = lbot;
+       ind = argp[1].val;
+       atm = argp->val;
+       switch (TYPE(atm)) {
+       case DTPR:
+               pptr = atm->d.cdr;
+               disemp = TRUE;
+               break;
+       case ATOM:
+               if((lispval)atm==nil)
+                       pptr = nilplist;
+               else
+                       pptr = atm->a.plist;
+               break;
+       default:
+               errorh1(Vermisc, "remprop: Illegal first argument :",
+                      nil, FALSE, 0, atm);
+       }
+       opptr = nil;
+       if (pptr==nil) 
+               return(nil);
+       while(TRUE) {
+               if (TYPE(pptr->d.cdr)!=DTPR)
+                       errorh1(Vermisc, "remprop: Bad property list",
+                              nil, FALSE, 0,atm);
+               if (pptr->d.car == ind) {
+                       if( opptr != nil)
+                               opptr->d.cdr = pptr->d.cdr->d.cdr;
+                       else if(disemp)
+                               atm->d.cdr = pptr->d.cdr->d.cdr;
+                       else if(atm==nil)
+                               nilplist = pptr->d.cdr->d.cdr;
+                       else
+                               atm->a.plist = pptr->d.cdr->d.cdr;
+                       return(pptr->d.cdr);
+               }
+               if ((pptr->d.cdr)->d.cdr == nil) return(nil);
+               opptr = pptr->d.cdr;
+               pptr = (pptr->d.cdr)->d.cdr;
+       }
+}
+
+lispval
+Lbcdad()
+{
+       lispval ret, temp;
+
+       chkarg(1,"bcdad");
+       temp = lbot->val;
+       if (TYPE(temp)!=ATOM)
+               error("ONLY ATOMS HAVE FUNCTION BINDINGS", FALSE);
+       temp = temp->a.fnbnd;
+       if (TYPE(temp)!=BCD)
+               return(nil);
+       ret = newint();
+       ret->i = (int)temp;
+       return(ret);
+}
+
+lispval
+Lstringp()
+{
+       chkarg(1,"stringp");
+       if (TYPE(lbot->val)==STRNG)
+               return(tatom);
+       return(nil);
+}
+
+lispval
+Lsymbolp()
+{
+       chkarg(1,"symbolp");
+       if (TYPE(lbot->val)==ATOM)
+               return(tatom);
+       return(nil);
+}
+
+lispval
+Lrematom()
+{
+       register lispval temp;
+
+       chkarg(1,"rematom");
+       temp = lbot->val;
+       if (TYPE(temp)!=ATOM)
+               return(nil);
+       temp->a.fnbnd = nil;
+       temp->a.pname = (char *)CNIL;
+       temp->a.plist = nil;
+       (atom_items->i)--;
+       (atom_str.space_left)++;
+       temp->a.clb=(lispval)atom_str.next_free;
+       atom_str.next_free=(char *) temp;
+       return(tatom);
+}
+
+#define QUTMASK 0200
+#define VNUM 0000
+
+lispval
+Lprname()
+{
+       lispval a, ret;
+       register lispval work, prev;
+       char    *front, *temp; int clean;
+       char ctemp[100];
+       extern unsigned char *ctable;
+       Savestack(2);
+
+       chkarg(1,"prname");
+       a = lbot->val;
+       switch (TYPE(a)) {
+               case INT:
+                       sprintf(ctemp,"%d",a->i);
+                       break;
+
+               case DOUB:
+                       sprintf(ctemp,"%f",a->r);
+                       break;
+       
+               case ATOM:
+                       temp = front = a->a.pname;
+                       clean = *temp;
+                       if (*temp == '-') temp++;
+                       clean = clean && (ctable[*temp] != VNUM);
+                       while (clean && *temp)
+                               clean = (!(ctable[*temp++] & QUTMASK));
+                       if (clean)
+                               strcpyn(ctemp, front, 99);
+                       else    
+                               sprintf(ctemp,"\"%s\"",front);
+                       break;
+       
+               default:
+                       error("prname does not support this type", FALSE);
+       }
+       temp = ctemp;
+       protect(ret = prev = newdot());
+       while (*temp) {
+               prev->d.cdr = work = newdot();
+               strbuf[0] = *temp++;
+               strbuf[1] = 0;
+               work->d.car = getatom(FALSE);
+               work->d.cdr = nil;
+               prev = work;
+       }
+       Restorestack();
+       return(ret->d.cdr);
+}
+
+lispval
+Lexit()
+{
+       register lispval handy;
+       if(np-lbot==0) franzexit(0);
+       handy = lbot->val;
+       if(TYPE(handy)==INT)
+               franzexit((int) handy->i);
+       franzexit(-1);
+}
+lispval
+Iimplode(unintern)
+{
+       register lispval handy, work;
+       register char *cp = strbuf;
+       extern int atmlen;      /* used by newatom and getatom */
+
+       chkarg(1,"implode");
+       for(handy = lbot->val; handy!=nil; handy = handy->d.cdr)
+       {
+               work = handy->d.car;
+               if(cp >= endstrb)
+                       errorh1(Vermisc,"maknam/implode argument exceeds buffer",nil,FALSE,43,lbot->val);
+       again:
+               switch(TYPE(work))
+               {
+               case ATOM:
+                       *cp++ = work->a.pname[0];
+                       break;
+               case SDOT:
+               case INT:
+                       *cp++ = work->i;
+                       break;
+               case STRNG:
+                       *cp++ = * (char *) work;
+                       break;
+               default:
+                       work = errorh1(Vermisc,"implode/maknam: Illegal type for this arg:",nil,FALSE,44,work);
+                       goto again;
+               }
+       }
+       *cp = 0;
+       if(unintern) return((lispval)newatom(FALSE));
+       else return((lispval) getatom(FALSE));
+}
+
+lispval
+Lmaknam()
+{
+       return(Iimplode(TRUE));         /* unintern result */
+}
+
+lispval
+Limplode()
+{
+       return(Iimplode(FALSE));        /* intern result */
+}
+
+lispval
+Lintern()
+{
+       register int hash;
+       register lispval handy,atpr;
+
+
+       chkarg(1,"intern");
+       if(TYPE(handy=lbot->val) != ATOM)
+               errorh1(Vermisc,"non atom to intern ",nil,FALSE,0,handy);
+       /* compute hash of pname of arg */
+       hash = hashfcn(handy->a.pname);
+
+       /* search for atom with same pname on hash list */
+
+       atpr = (lispval) hasht[hash];
+       for(atpr = (lispval) hasht[hash] 
+                ; atpr != CNIL 
+                ; atpr = (lispval)atpr->a.hshlnk)
+       {
+               if(strcmp(atpr->a.pname,handy->a.pname) == 0) return(atpr);
+       }
+       
+       /* not there yet, put the given one on */
+
+       handy->a.hshlnk = hasht[hash];
+       hasht[hash] = (struct atom *)handy;
+       return(handy);
+}
+
+/*** Ibindvars :: lambda bind values to variables
+       called with a list of variables and values.
+       does the special binding and returns a fixnum which represents
+       the value of bnp before the binding
+       Use by compiled progv's.
+ ***/
+lispval
+Ibindvars()
+{
+    register lispval vars,vals,handy;
+    struct nament *oldbnp = bnp;
+
+    chkarg(2,"int:bindvars");
+
+    vars = lbot[0].val;
+    vals = lbot[1].val;
+
+    if(vars == nil) return(inewint(oldbnp));
+
+    if(TYPE(vars) != DTPR)
+      errorh1(Vermisc,"progv (int:bindvars): bad first argument ", nil,
+               FALSE,0,vars);
+   if((vals != nil) && (TYPE(vals) != DTPR))
+     errorh1(Vermisc,"progv (int:bindvars): bad second argument ",nil,
+               FALSE,0,vals);
+
+   for( ; vars != nil ; vars = vars->d.cdr , vals=vals->d.cdr)
+   {
+       handy = vars->d.car;
+       if(TYPE(handy) != ATOM)
+          errorh1(Vermisc,"progv (int:bindvars): non symbol argument to bind ",
+               nil,FALSE,0,handy);
+       PUSHDOWN(handy,vals->d.car);
+   }
+   return(inewint(oldbnp));
+}
+
+
+/*** Iunbindvars :: unbind the variable stacked by Ibindvars
+     called by compiled progv's
+ ***/
+lispval
+Iunbindvars()
+{
+    struct nament *oldbnp;
+    
+    chkarg(1,"int:unbindvars");
+    oldbnp = (struct nament *) (lbot[0].val->i);
+    if((oldbnp < orgbnp)  || ( oldbnp > bnp))
+       errorh1(Vermisc,"int:unbindvars: bad bnp value given ",nil,FALSE,0,
+                       lbot[0].val);
+    popnames(oldbnp);
+    return(nil);
+}
+
+/*
+ * (time-string ['x_milliseconds])
+ * if given no argument, returns the current time as a string
+ * if given an argument which is a fixnum representing the current time
+ * as a fixnum, it generates a string from that
+ *
+ * the format of the string returned is that defined in the Unix manual
+ * except the trailing newline is removed.
+ *
+ */
+lispval
+Ltimestr()
+{
+    long timevalue;
+    char *retval;
+    
+    switch(np-lbot)
+    {
+       case 0: time(&timevalue);
+               break;
+       case 1: while (TYPE(lbot[0].val) != INT)
+                 lbot[0].val =
+                    errorh(Vermisc,"time-string: non fixnum argument ",
+                               nil,TRUE,0,lbot[0].val);
+               timevalue = lbot[0].val->i;
+               break;
+       default:
+               argerr("time-string");
+    }
+
+    retval = (char *) ctime(&timevalue);
+    /* remove newline character */
+    retval[strlen(retval)-1] = '\0';
+    return((lispval) inewstr(retval));
+}
diff --git a/usr/src/ucb/lisp/franz/lam8.c b/usr/src/ucb/lisp/franz/lam8.c
new file mode 100644 (file)
index 0000000..0a75516
--- /dev/null
@@ -0,0 +1,1246 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lam8.c,v 1.9 83/09/12 14:16:52 sklower Exp $";
+#endif
+
+/*                                     -[Fri Aug 12 07:54:00 1983 by jkf]-
+ *     lam8.c                          $Locker:  $
+ * lambda functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "frame.h"
+
+/* various functions from the c math library */
+double sin(),cos(),asin(),acos(),atan2(),sqrt(), log(), exp();
+extern int current;
+
+lispval Imath(func)
+double (*func)();
+{
+       register lispval handy;
+       register double res;
+       chkarg(1,"Math functions");
+
+       switch(TYPE(handy=lbot->val)) {
+        case INT: res = func((double)handy->i); 
+                  break;
+
+        case DOUB: res = func(handy->r);
+                  break;
+
+        default:  error("Non fixnum or flonum to math function",FALSE);
+       }
+       handy = newdoub();
+       handy->r = res;
+       return(handy);
+}
+lispval Lsin()
+{
+       return(Imath(sin));
+}
+
+lispval Lcos()
+{
+       return(Imath(cos));
+}
+
+lispval Lasin()
+{
+       return(Imath(asin));
+}
+
+lispval Lacos()
+{
+       return(Imath(acos));
+}
+
+lispval Lsqrt()
+{
+       return(Imath(sqrt));
+}
+lispval Lexp()
+{
+       return(Imath(exp));
+}
+
+lispval Llog()
+{
+       return(Imath(log));
+}
+
+/* although we call this atan, it is really atan2 to the c-world,
+   that is, it takes two args
+ */
+lispval Latan()
+{
+       register lispval arg;
+       register double arg1v;
+       register double res;
+       chkarg(2,"arctan");
+
+       switch(TYPE(arg=lbot->val)) {
+
+       case INT:  arg1v = (double) arg->i;
+                  break;
+
+       case DOUB: arg1v = arg->r;
+                  break;
+
+       default:   error("Non fixnum or flonum arg to atan2",FALSE);
+       }
+
+       switch(TYPE(arg = (lbot+1)->val)) {
+
+       case INT: res = atan2(arg1v,(double) arg->i);
+                 break;
+
+       case DOUB: res = atan2(arg1v, arg->r);
+                 break;
+
+       default:  error("Non fixnum or flonum to atan2",FALSE);
+       }
+       arg = newdoub();
+       arg->r = res;
+       return(arg);
+}
+
+/* (random) returns a fixnum in the range -2**30 to 2**30 -1
+   (random fixnum) returns a fixnum in the range 0 to fixnum-1
+ */
+lispval
+Lrandom()
+{
+       register int curval;
+       float pow();
+
+       curval = rand();        /* get numb from 0 to 2**31-1 */
+
+       if(np==lbot) return(inewint(curval-(int)pow((double)2,(double)30)));
+
+       if((TYPE(lbot->val) != INT)
+           || (lbot->val->i <= 0)) errorh1(Vermisc,"random: non fixnum arg:",
+                                                nil, FALSE, 0, lbot->val);
+
+       return(inewint(curval % lbot->val->i )); 
+
+}
+lispval
+Lmakunb()
+{
+       register lispval work;
+
+       chkarg(1,"makunbound");
+       work = lbot->val;
+       if(work==nil || (TYPE(work)!=ATOM))
+               return(work);
+       work->a.clb = CNIL;
+       return(work);
+}
+
+lispval
+Lfseek()
+{
+
+       FILE *f;
+       long offset, whence;
+       lispval retp;
+
+       chkarg(3,"fseek");                      /* Make sure there are three arguments*/
+
+       f = lbot->val->p;               /* Get first argument into f */
+       if (TYPE(lbot->val)!=PORT)      /* Check type of first */
+               error("fseek: First argument must be a port.",FALSE);
+
+       offset = lbot[1].val->i;        /* Get second argument */
+       if (TYPE(lbot[1].val)!=INT)
+               error("fseek: Second argument must be an integer.",FALSE);
+
+       whence = lbot[2].val->i;        /* Get last arg */
+       if (TYPE(lbot[2].val)!=INT)
+               error("fseek: Third argument must be an integer.",FALSE);
+
+       if (fseek(f, offset, (int)whence) == -1)
+               error("fseek: Illegal parameters.",FALSE);
+
+       retp = inewint(ftell(f));
+
+       return((lispval) retp);
+}
+
+/* function hashtabstat  : return list of number of members in  each bucket */
+lispval Lhashst()
+{
+       register lispval handy,cur;
+       register struct atom *pnt;
+       int i,cnt;
+       extern int hashtop;
+       Savestack(3);
+
+       handy = newdot();
+       protect(handy);
+       cur = handy;
+       for(i = 0; i < hashtop; i++)
+       {
+           pnt = hasht[i];
+           for(cnt = 0; pnt != (struct atom *) CNIL ; pnt=pnt->hshlnk , cnt++);
+           cur->d.cdr = newdot();
+           cur = cur->d.cdr;
+           cur->d.car = inewint(cnt);
+       }
+       cur->d.cdr = nil;
+       Restorestack();
+       return(handy->d.cdr);
+}
+
+
+/* Lctcherr
+  this routine should only be called by the unwind protect simulation
+  lisp code
+  It is called after an unwind-protect frame has been entered and
+  evalated and we want to get on with the error or throw
+  We only handle the case where there are 0 to 2 extra arguments to the
+  error call.
+*/
+lispval
+Lctcherr()
+{
+       register lispval handy;
+       lispval type,messg,valret,contuab,uniqid,datum1,datum2;
+
+       chkarg(1,"I-throw-err");
+
+       handy = lbot->val;
+       
+       if(TYPE(handy->d.car) == INT)
+       {       /* continuing a non error (throw,reset, etc) */
+               Inonlocalgo((int)handy->d.car->i,
+                           handy->d.cdr->d.car, 
+                           handy->d.cdr->d.cdr->d.car);
+               /* NOT REACHED */
+       }
+
+       if(handy->d.car != nil)
+       {
+           errorh1(Vermisc,"I-do-throw: first element not fixnum or nil",
+                  nil,FALSE,0,handy);
+       }
+           
+       /* decode the arg list */
+       handy = handy->d.cdr;
+       type = handy->d.car;
+       handy = handy->d.cdr;
+       messg = handy->d.car;
+       handy = handy->d.cdr;
+       valret = handy->d.car;
+       handy = handy->d.cdr;
+       contuab = handy->d.car;
+       handy = handy->d.cdr;
+       uniqid = handy->d.car;
+       handy = handy->d.cdr;
+
+       /* if not extra args */
+       if(handy == nil)
+       {
+         errorh(type,messg->a.pname,valret,(int)contuab->i,(int)uniqid->i);
+       }
+       datum1 = handy->d.car;
+       handy = handy->d.cdr;
+
+       /* if one extra arg */
+       if(handy == nil)
+       {
+         errorh1(type,messg->a.pname,valret,(int)contuab->i,(int)uniqid->i,datum1);
+       }
+
+       /* if two or more extra args, just use first 2 */
+       datum2 = handy->d.car;
+       errorh2(type,messg->a.pname,valret,(int)contuab->i,(int)uniqid->i,datum1,datum2);
+}
+
+/*
+ *     (*makhunk '<fixnum>)
+ *                       <fixnum>
+ * Create a hunk of size 2       . <fixnum> must be between 0 and 6.
+ *
+ */
+
+lispval
+LMakhunk()
+{
+       register int hsize, hcntr;
+       register lispval result;
+
+       chkarg(1,"Makehunk");
+       if (TYPE(lbot->val)==INT)
+       {
+               hsize = lbot->val->i;           /* size of hunk (0-6) */
+               if ((hsize >= 0) && (hsize <= 6))
+               {
+                       result = newhunk(hsize);
+                       hsize = 2 << hsize;     /* size of hunk (2-128) */
+                       for (hcntr = 0; hcntr < hsize; hcntr++)
+                               result->h.hunk[hcntr] = hunkfree;
+               }
+               else
+                       error("*makhunk: Illegal hunk size", FALSE);
+       return(result);
+       }
+       else
+               error("*makhunk: First arg must be an fixnum",FALSE);
+       /* NOTREACHED */
+}
+
+/*
+ *     (cxr '<fixnum> '<hunk>)
+ * Returns the <fixnum>'th element of <hunk>
+ *
+ */
+lispval
+Lcxr()
+{
+       register lispval temp;
+
+       chkarg(2,"cxr");
+       if (TYPE(lbot->val)!=INT)
+               error("cxr: First arg must be a fixnum", FALSE);
+       else
+       {
+               if (! HUNKP(lbot[1].val))
+                       error("cxr: Second arg must be a hunk", FALSE);
+               else
+                       if ( (lbot->val->i >= 0) &&
+                            (lbot->val->i < (2 << HUNKSIZE(lbot[1].val))) )
+                       {
+                               temp = lbot[1].val->h.hunk[lbot->val->i];
+                               if (temp != hunkfree)
+                                       return(temp);
+                               else
+                                       error("cxr: Arg outside of hunk range",
+                                             FALSE);
+                       }
+                       else
+                               error("cxr: Arg outside of hunk range", FALSE);
+       }
+       /* NOTREACHED */
+}
+
+/*
+ *     (rplacx '<fixnum> '<hunk> '<expr>)
+ * Replaces the <fixnum>'th element of <hunk> with <expr>.
+ *
+ */
+lispval
+Lrplacx()
+{
+       lispval *handy;
+       chkarg(3,"rplacx");
+       if (TYPE(lbot->val)!=INT)
+               error("rplacx: First arg must be a fixnum", FALSE);
+       else
+       {
+               if (! HUNKP(lbot[1].val))
+                       error("rplacx: Second arg must be a hunk", FALSE);
+               else
+               {
+                       if ( (lbot->val->i >= 0) &&
+                            (lbot->val->i < (2 << HUNKSIZE(lbot[1].val))) )
+                       {
+                          if (*(handy = &(lbot[1].val->h.hunk[lbot->val->i]))
+                                       != hunkfree)
+                                   *handy  = lbot[2].val;
+                               else
+                                       error("rplacx: Arg outside hunk range", FALSE);
+                       }
+                       else
+                               error("rplacx: Arg outside hunk range", FALSE);
+               }
+       }
+       return(lbot[1].val);
+}
+
+/*
+ *     (*rplacx '<fixnum> '<hunk> '<expr>)
+ * Replaces the <fixnum>'th element of <hunk> with <expr>. This is the
+ * same as (rplacx ...) except with this function you can replace EMPTY's.
+ *
+ */
+lispval
+Lstarrpx()
+{
+       chkarg(3,"*rplacx");
+       if (TYPE(lbot->val)!=INT)
+               error("*rplacx: First arg must be a fixnum", FALSE);
+       else
+       {
+               if (! HUNKP(lbot[1].val))
+                       error("*rplacx: Second arg must be a hunk", FALSE);
+               else
+               {
+                       if ( (lbot->val->i >= 0) &&
+                            (lbot->val->i < (2 << HUNKSIZE(lbot[1].val))) )
+                               lbot[1].val->h.hunk[lbot->val->i] = lbot[2].val;
+                       else
+                               error("*rplacx: Arg outside hunk range", FALSE);
+               }
+       }
+       return(lbot[1].val);
+}
+
+/*
+ *     (hunksize '<hunk>)
+ * Returns the size of <hunk>
+ *
+ */
+lispval
+Lhunksize()
+{
+       register int size,i;
+
+       chkarg(1,"hunksize");
+       if (HUNKP(lbot->val))
+       {
+               size = 2 << HUNKSIZE(lbot->val);
+               for (i = size-1; i >= 0; i--)
+               {
+                       if (lbot->val->h.hunk[i] != hunkfree)
+                       {
+                               size = i + 1;
+                               break;
+                       }
+               }
+               return( inewint(size) );
+       }
+       else
+               error("hunksize: First argument must me a hunk", FALSE);
+                       /* NOTREACHED */
+}
+
+/*
+ * (hunk-to-list 'hunk)        returns a list of the hunk elements
+ */
+lispval
+Lhtol()
+{
+    register lispval handy,retval,last;
+    register int i;
+    int size;
+    Savestack(4);
+
+    chkarg(1,"hunk-to-list");
+    handy = lbot->val;
+    if(!(HUNKP(handy)))
+       errorh1(Vermisc,"hunk-to-list: non hunk argument: ", nil,0,FALSE,
+                       handy);
+    size = 2 << HUNKSIZE(handy);
+    retval = nil;
+    for(i=0 ; i < size ; i++)
+    {
+       if(handy->h.hunk[i] != hunkfree)
+       {
+           if(retval==nil)
+           {
+               protect(retval=newdot());
+               last = retval;
+           }
+           else {
+               last = (last->d.cdr = newdot());
+           }
+           last->d.car = handy->h.hunk[i];
+       }
+       else break;
+    }
+    Restorestack();
+    return(retval);
+}
+           
+/*
+ *     (fileopen  filename mode)
+ * open a file for read, write, or append the arguments can be either
+ * strings or atoms.
+ */
+lispval
+Lfileopen()
+{
+       FILE *port;
+       register lispval name;
+       register lispval mode;
+       register char *namech;
+       register char *modech;
+
+       chkarg(2,"fileopen");
+       name = lbot->val;
+       mode = lbot[1].val;
+
+       namech = (char *) verify(name,"fileopen:args must be atoms or strings");
+       modech = (char *) verify(mode,"fileopen:args must be atoms or strings");
+
+       while (modech[0] != 'r' && modech[0] != 'w' && modech[0] != 'a')
+       {
+               mode = errorh(Vermisc,"Modes are only r, w, a.",nil,TRUE,31);
+               modech = (char *) verify(mode,"fileopen:args must be atoms or strings");
+       }
+
+       while ((port = fopen(namech, modech)) == NULL)
+       {
+           name = errorh1(Vermisc,"Unable to open file.",nil,TRUE,31,name);
+           namech = (char *) verify(name,"fileopen:args must be atoms or strings");
+       }
+           /* xports is a FILE *, cc complains about adding pointers */
+
+       ioname[PN(port)] = (lispval) inewstr(namech);   /* remember name */
+       return( (lispval) (xports + (port - _iob)));
+}
+
+/*
+ *     (*invmod '<number> '<modulus>)
+ * This function returns the inverse of  <number>
+ * mod <modulus> in balanced representation
+ * It is used in vaxima as a speed enhancement.
+ */
+
+static lispval
+Ibalmod(invmodp)
+{
+       register long mod_div_2, number, modulus;
+
+       chkarg(2,"*mod");
+       if ((TYPE(lbot->val) == INT) && (TYPE(lbot[1].val) == INT))
+       {
+               modulus = lbot[1].val->i;
+               if(invmodp) number = invmod(lbot->val->i , modulus);
+               else number = lbot->val->i % modulus;
+               mod_div_2 = modulus / 2;
+               if (number < 0)
+               {
+                       if (number < (-mod_div_2))
+                               number += modulus;
+               }
+               else
+               {
+                       if (number > mod_div_2)
+                               number -= modulus;
+               }
+               return( inewint(number) );
+       }
+       else
+               error("*mod: Arguments must be fixnums", FALSE);
+       /* NOTREACHED */
+}
+
+invmod (n,modulus)
+long n , modulus;
+
+{ 
+       long a1,a2,a3,y1,y2,y3,q;
+
+       a1 = modulus; 
+       a2 = n; 
+       y1 = 0; 
+       y2= 1; 
+       goto step3;
+step2: 
+       q = a1 /a2; /*truncated quotient */
+       a3= mmuladd(modulus-a2,q,a1,modulus);
+       y3= mmuladd(modulus-y2,q,y1,modulus);
+       a1 = a2; 
+       a2= a3; 
+       y1=y2; 
+       y2=y3;
+step3: 
+       if (a2==0) error("invmod: inverse of zero divisor",TRUE);
+       else if (a2 != 1) goto step2;
+       else return (y2);
+       /* NOTREACHED */
+}
+
+lispval
+Lstarinvmod()
+{
+       return(Ibalmod(TRUE));
+}
+
+/*
+ *     (*mod '<number> '<modulus>)
+ * This function returns <number> mod <modulus> (for balanced modulus).
+ * It is used in vaxima as a speed enhancement.
+ */
+lispval
+LstarMod()
+{
+       return(Ibalmod(FALSE));
+}
+
+lispval
+Llsh()
+{
+       register struct argent *mylbot = lbot;
+       int val,shift;
+
+       chkarg(2,"lsh");
+       if((TYPE(mylbot->val) != INT) || (TYPE(mylbot[1].val) != INT))
+               errorh2(Vermisc,
+                      "Non ints to lsh",
+                      nil,FALSE,0,mylbot->val,mylbot[1].val);
+       val = mylbot[0].val->i;
+       shift = mylbot[1].val->i;
+       if(shift < -32 || shift > 32)
+         return(inewint(0));
+       if (shift < 0)
+               val = val >> -shift;
+       else
+               val = val << shift;
+       if((val < 0) && (shift < 0))
+       {       /* special case: the vax doesn't have a logical shift
+                  instruction, so we must zero out the ones which
+                  will propogate from the sign position
+               */
+               return(inewint ( val & ~(0x80000000 << (shift+1))));
+       }
+       else return( inewint(val));
+}
+
+/* very temporary function to test the validity of the bind stack */
+
+bndchk()
+{  
+       register struct nament *npt;
+       register lispval in2;
+
+       in2 = inewint(200);
+       for(npt=orgbnp; npt < bnp; npt++)
+       {  if((int) npt->atm < (int) in2) abort();
+       }
+}
+
+/*
+ *     formatted printer for lisp data
+ *    use: (cprintf formatstring datum [port])
+ */
+lispval
+Lcprintf()
+{
+    FILE *p;
+    char *fstrng;
+    lispval v;
+    if(np-lbot == 2) protect(nil);     /* write to standard output port */
+    chkarg(3,"cprintf");
+
+    fstrng = (char *)verify(lbot->val,"cprintf: first arg not string or symbol");
+
+    p = okport(lbot[2].val,okport(Vpoport->a.clb,poport));
+
+    switch(TYPE(v=lbot[1].val)) {
+
+       case INT:  fprintf(p,fstrng,v->i);
+                  break;
+
+       case DOUB: fprintf(p,fstrng,v->r);
+                  break;
+
+       case ATOM: fprintf(p,fstrng,v->a.pname);
+                  break;
+
+       case STRNG:fprintf(p,fstrng,v);
+                  break;
+
+       default:   error("cprintf: Illegal second argument",FALSE);
+   };
+
+   return(lbot[1].val);
+}
+
+
+/*
+ * C style sprintf: (sprintf "format" {<arg-list>})
+ *
+ * This function stacks the arguments onto the C stack in reverse
+ * order and then calls sprintf with one argument...This is what the
+ * C compiler does, so it works just fine. The return value is the
+ * string that is the result of the sprintf.
+ */
+lispval
+Lsprintf()
+{
+       register struct argent *argp;
+       register int j;
+       char sbuf[600], *sprintf();                     /* better way? */
+       Keepxs();
+
+       if (np-lbot == 0) {
+               argerr("sprintf");
+       }
+       if (TYPE(lbot->val)==STRNG || TYPE(lbot->val)==INT) {
+               for (argp = np-1; argp >= lbot; argp--) {
+                       switch(TYPE(argp->val)) {
+                         case ATOM:
+                               stack((long)argp->val->a.pname);
+                               break;
+
+                         case DOUB:
+#ifndef SPISFP
+                               stack(argp->val->r);
+#else
+                               {double rr = argp->val->r;
+                               stack(((long *)&rr)[1]);
+                               stack(((long *)&rr)[0]);}
+#endif
+                               break;
+
+                         case INT:
+                               stack(argp->val->i);
+                               break;
+
+                         case STRNG:
+                               stack((long)argp->val);
+                               break;
+
+                         default:
+                               error("sprintf: Bad data type to sprintf",
+                                               FALSE);
+                       }
+               }
+               sprintf(sbuf);
+               for (j = 0; j < np-lbot; j++)
+                       unstack();
+       } else
+               error("sprintf: First arg must be an atom or string", FALSE);
+       Freexs();
+       return ((lispval) inewstr(sbuf));
+}
+
+lispval
+Lprobef()
+{
+       char *name;
+       chkarg(1,"probef");
+
+       name = (char *)verify(lbot->val,"probef: not symbol or string arg ");
+
+       if(access(name,0) == 0) return(tatom);
+       else return(nil);
+}
+
+lispval
+Lsubstring()
+{      register char *name;
+       register lispval index,length;
+       int restofstring = FALSE;
+       int len,ind,reallen;
+
+       switch (np-lbot) 
+       {
+         case 2: restofstring = TRUE;
+                 break;
+
+         case 3: break;
+
+         default: chkarg(3,"substring");
+       }
+
+       name = (char *)verify(lbot[0].val,"substring: not symbol or string arg ");
+
+       while (TYPE(index = lbot[1].val) != INT)
+       {  lbot[1].val = errorh1(Vermisc,"substring: non integer index ",nil,
+                                                   TRUE,0,index);
+       }
+
+       len = strlen(name);
+       ind = index->i;
+
+       if(ind < 0) ind = len+1 + ind;
+
+       if(ind < 1 || ind > len) return(nil);   /*index out of bounds*/
+       if(restofstring) return((lispval)inewstr(name+ind-1));
+
+       while (TYPE(length = lbot[2].val) != INT)
+       { lbot[2].val = errorh1(Vermisc,"substring: not integer length ",nil,
+                                                  TRUE,0,length);
+       }
+
+       if((reallen = length->i ) < 0 || (reallen + ind) > len)
+         return((lispval)inewstr(name+ind-1));
+
+       strncpy(strbuf,name+ind-1,reallen);
+       strbuf[reallen] = '\0';
+       return((lispval)newstr(0));
+}
+
+/*
+ * This is substringn
+ */
+lispval
+Lsstrn()
+{
+       register char *name;
+       register int len,ind,reallen;
+       lispval index,length;
+       int restofstring = FALSE;
+       Savestack(4);
+
+       if((np-lbot) == 2) restofstring = TRUE;
+       else { chkarg(3,"substringn");}
+
+       name = (char *) verify(lbot[0].val,"substringn: non symbol or string arg ");
+
+       while (TYPE(index = lbot[1].val) != INT)
+       {  lbot[1].val = errorh1(Vermisc,"substringn: non integer index ",nil,
+                                                   TRUE,0,index);
+       }
+
+       if(!restofstring)
+       {
+           while (TYPE(length = lbot[2].val) != INT)
+           { lbot[2].val = errorh1(Vermisc,"substringn: not integer length ",
+                                                       nil, TRUE,0,length);
+           }
+           reallen = length->i;
+       }
+       else reallen = -1;
+
+       len = strlen(name);
+       ind = index->i;
+       if(ind < 0) ind = len + 1 + ind;
+       if( ind < 1 || ind > len) return(nil);
+
+       if(reallen == 0) 
+           return((lispval)inewint(*(name + ind - 1)));
+       else {
+           char *pnt = name + ind - 1;
+           char *last = name + len -1;
+           lispval cur,start;
+
+           protect(cur = start = newdot());
+           cur->d.car = inewint(*pnt);
+           while(++pnt <= last && --reallen != 0)
+           {
+              cur->d.cdr = newdot();
+              cur = cur->d.cdr;
+              cur->d.car = inewint(*pnt);
+           }
+           Restorestack();
+           return(start);
+       }
+
+}
+
+lispval Ipurcopy();
+
+
+lispval
+Lpurcopy()
+{
+       chkarg(1,"purcopy");
+       return(Ipurcopy(lbot[0].val));
+}
+           
+lispval
+Ipurcopy(handy)
+lispval handy;
+{
+    extern int *beginsweep;
+    register lispval retv, curv, lv;
+    int i,size;
+
+    switch(TYPE(handy)) {
+
+       case DTPR:
+                  retv = curv = pnewdot();
+                  lv = handy;
+                  while(TRUE)
+                  {
+                     curv->d.car = Ipurcopy(lv->d.car);
+                     if(TYPE(lv = lv->d.cdr) == DTPR)
+                     {
+                         curv->d.cdr = pnewdot();
+                         curv = curv->d.cdr;
+                     }
+                     else {
+                         curv->d.cdr = Ipurcopy(lv);
+                         break;
+                     }
+                   }
+                   return(retv);
+
+       case SDOT:
+                   retv = curv = pnewsdot();
+                   lv = handy;
+                   while(TRUE)
+                   {
+                       curv->s.I = lv->s.I;
+                       if(lv->s.CDR == (lispval) 0) break;
+                       lv = lv->s.CDR;
+                       curv->s.CDR = pnewdot();
+                       curv = curv->s.CDR;
+                   }
+                   curv->s.CDR = 0;
+                   return(retv);
+
+       case INT:
+                   if((int *)handy < beginsweep) return(handy);
+                   retv = pnewint();
+                   retv->i = handy->i;
+                   return(retv);
+
+       case DOUB:
+                   retv = pnewdoub();
+                   retv->r = handy->r;
+                   return(retv);
+
+       case HUNK2:
+               i = 0;
+               goto hunkit;
+
+       case HUNK4:
+               i = 1;
+               goto hunkit;
+
+       case HUNK8:
+               i = 2;
+               goto hunkit;
+
+       case HUNK16:
+               i = 3;
+               goto hunkit;
+
+       case HUNK32:
+               i = 4;
+               goto hunkit;
+
+       case HUNK64:
+               i = 5;
+               goto hunkit;
+
+       case HUNK128:
+               i = 6; 
+
+           hunkit:
+               retv = pnewhunk(i);
+               size = 2 << i ; /* number of elements to copy over */
+               for( i = 0; i < size ; i++)
+               {
+                   retv->h.hunk[i] = Ipurcopy(handy->h.hunk[i]);
+               }
+               return(retv);
+
+
+
+       case STRNG:
+#ifdef GCSTRINGS
+               { extern char purepage[];
+
+                 if(purepage[((int)handy)>>9]==0)
+                       return((lispval)pinewstr((char *)handy));}
+               
+#endif
+       case ATOM: 
+       case BCD:
+       case PORT:
+           return(handy);      /* We don't want to purcopy these, yet
+                                * it won't hurt if we don't mark them
+                                * since they either aren't swept or 
+                                * will be marked in a special way 
+                                */
+       case ARRAY:
+               error("purcopy: can't purcopy array structures",FALSE);
+
+       default:
+               error(" bad type to purcopy ",FALSE);
+       /* NOTREACHED */
+    }
+}
+
+/*
+ * Lpurep returns t if the given arg is in pure space
+ */
+lispval
+Lpurep()
+{
+    lispval Ipurep();
+
+    chkarg(1,"purep");
+    return(Ipurep(lbot->val));
+}
+
+
+
+/* vector functions */
+lispval newvec(), nveci(), Inewvector();
+
+/* vector creation and initialization functions */
+lispval
+Lnvec()
+{
+    return(Inewvector(3));
+}
+
+lispval
+Lnvecb()
+{
+    return(Inewvector(0));
+}
+
+lispval
+Lnvecw()
+{
+    return(Inewvector(1));
+}
+
+lispval
+Lnvecl()
+{
+    return(Inewvector(2));
+}
+
+/*
+ * (new-vector 'x_size ['g_fill] ['g_prop])
+ * class = 0: byte \
+ *       = 1: word  > immediate
+ *       = 2: long /
+ *      = 3: long
+ */
+lispval
+Inewvector(class)
+{
+    register int i;
+    register lispval handy;
+    register lispval *handy2;
+    char *chandy;
+    short *whandy;
+    long *lhandy;
+    lispval sizearg, fillarg, proparg;
+    int size, vsize;
+
+    fillarg = proparg = nil;
+    
+    switch(np-lbot) {
+       case 3: proparg = lbot[2].val;
+       case 2: fillarg = lbot[1].val;
+       case 1: sizearg = lbot[0].val;
+               break;
+       default: argerr("new-vector");
+    }
+    
+    while((TYPE(sizearg) != INT) || sizearg->i < 0)
+       sizearg = errorh1(Vermisc,"new-vector: bad size for vector ",nil,
+                               TRUE,0,sizearg);
+    size = sizearg->i;
+    switch(class)
+    {
+       case 0: vsize = size * sizeof(char);
+               break;
+       case 1: vsize = size * sizeof(short);
+               break;
+       default: vsize = size * sizeof(long);
+               break;
+    }
+    
+    if(class != 3) handy = nveci(vsize);
+    else handy = newvec(vsize);
+    
+    switch(class)
+    {
+       case 0: chandy = (char *)handy;
+               for(i = 0 ; i < size ; i++) *chandy++ = (char) (fillarg->i);
+               break;
+               
+       case 1: whandy = (short *)handy;
+               for(i = 0 ; i < size ; i++) *whandy++ = (short) (fillarg->i);
+               break;
+               
+       case 2: lhandy = (long *)handy;
+               for(i = 0 ; i < size ; i++) *lhandy++ = (fillarg->i);
+               break;
+
+       case 3: handy2 = (lispval *)handy;
+               for(i = 0 ; i < size ; i++) *handy2++ = fillarg;
+               break;
+    }
+    handy->v.vector[-1] = proparg;
+    return(handy);
+}
+
+lispval
+Lvectorp()
+{
+    chkarg(1,"vectorp");
+    if(TYPE(lbot->val) == VECTOR) return(tatom);
+    else return(nil);
+}
+
+lispval
+Lpvp()
+{
+    chkarg(1,"vectorip");
+    if(TYPE(lbot->val) == VECTORI) return(tatom);
+    else return(nil);
+}
+
+/*
+ * int:vref  vector[i] index class
+ *  class = 0: byte immed, 1: word immed, 2: long immed, 3: long
+ */
+lispval
+LIvref()
+{
+    register lispval vect;
+    register int index;
+    int class;
+    
+    chkarg(3,"int:vref");
+    vect = lbot[0].val;
+    index = lbot[1].val->i;
+    class = lbot[2].val->i;
+    switch(class)
+    {
+        case 0: return(inewint(vect->vb.vectorb[index]));
+        case 1: return(inewint(vect->vw.vectorw[index]));
+        case 2: return(inewint(vect->vl.vectorl[index]));
+       case 3: return(vect->v.vector[index]);
+    }
+    error("int:vref: impossible class detected",FALSE);
+    /* NOTREACHED */
+}
+
+/*
+ * int:vset vector[i] index value class
+ *  class = 0: byte immed, 1: word immed, 2: long immed, 3: long
+ */
+lispval
+LIvset()
+{
+    register lispval vect,value;
+    register int index;
+    int class;
+    
+    chkarg(4,"int:vset");
+    vect = lbot[0].val;
+    index = lbot[1].val->i;
+    value = lbot[2].val;
+    class = lbot[3].val->i;
+    switch(class)
+    {
+        case 0: vect->vb.vectorb[index] = (char)value->i;
+               break;
+        case 1: vect->vw.vectorw[index] = (short)value->i;
+               break;
+        case 2: vect->vl.vectorl[index] = value->i;
+               break;
+       case 3: vect->v.vector[index] = value;
+               break;
+    }
+    return(value);
+}
+
+/*
+ * LIvsize == (int:vsize 'vector 'x_shift)
+ *  return the vsize field of the vector shifted right by x_shift
+ */
+lispval
+LIvsize()
+{
+    int typ;
+    
+    chkarg(2,"int:vsize");
+    return(inewint((lbot[0].val->vl.vectorl[VSizeOff]) >> lbot[1].val->i));
+}
+
+lispval
+Lvprop()
+{
+    int typ;
+    chkarg(1,"vprop");
+    
+    if(((typ = TYPE(lbot->val)) != VECTOR) && (typ != VECTORI))
+       errorh1(Vermisc,"vprop: non vector argument: ", nil, FALSE,0,
+                       lbot->val);
+    return(lbot[0].val->v.vector[VPropOff]);
+}
+
+    
+lispval
+Lvsp()
+{
+       int typ;
+       lispval vector, property;
+       chkarg(2,"vsetprop");
+
+       vector = lbot->val;
+       property = lbot[1].val;
+       typ = TYPE(vector);
+
+       if(typ != VECTOR && typ !=VECTORI)
+               errorh1(Vermisc,"vsetprop: non vector argument: ",
+                               nil,FALSE,0,vector);
+       vector->v.vector[VPropOff] = property;
+       return(property);
+}
+
+
+/* vecequal
+ *  check if the two vector arguments are 'equal'
+ *  this is called by equal which has already checked that
+ *  the arguments are vector
+ */
+vecequal(v,w)
+lispval v,w;
+{
+    int i;
+    lispval vv, ww, ret;
+    int vsize = (int) v->v.vector[VSizeOff];
+    int wsize = (int) w->v.vector[VSizeOff];
+    struct argent *oldlbot = lbot;
+    lispval Lequal();
+
+    if(vsize != wsize) return(FALSE);
+
+    vsize /= sizeof(int);      /* determine number of entries */
+
+    for(i = 0 ; i < vsize ; i++)
+    {
+       vv = v->v.vector[i];
+       ww = w->v.vector[i];
+       /* avoid calling equal if they are eq */
+       if(vv != ww)
+       {
+           lbot = np;
+           protect(vv);
+           protect(ww);
+           ret = Lequal();
+           np = lbot;
+           lbot = oldlbot;
+           if(ret == nil)  return(FALSE);
+       }
+    }
+    return(TRUE);
+}
+            
+/* veciequal
+ *  check if the two vectori arguments are 'equal'
+ *  this is called by equal which has already checked that
+ *  the arguments are vector
+ *  Note: this would run faster if we did as many 'longword'
+ *  comparisons as possible and then did byte comparisons.
+ *  or if we used pointers instead of indexing.
+ */
+veciequal(v,w)
+lispval v,w;
+{
+    char vv, ww;
+    int i;
+    int vsize = (int) v->v.vector[VSizeOff];
+    int wsize = (int) w->v.vector[VSizeOff];
+
+    if(vsize != wsize) return(FALSE);
+
+
+    for(i = 0 ; i < vsize ; i++)
+    {
+       if(v->vb.vectorb[i] != w->vb.vectorb[i]) return(FALSE);
+    }
+    return(TRUE);
+}
diff --git a/usr/src/ucb/lisp/franz/lisp.c b/usr/src/ucb/lisp/franz/lisp.c
new file mode 100644 (file)
index 0000000..05db20d
--- /dev/null
@@ -0,0 +1,103 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: lisp.c,v 1.2 83/09/07 17:56:04 sklower Exp $";
+#endif
+
+/*                                     -[Sat Jan 29 13:24:33 1983 by jkf]-
+ *     lisp.c                          $Locker:  $
+ * main program
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include       "global.h"
+#include       "frame.h"
+
+/* main *****************************************************************/
+/* Execution of the lisp system begins here.  This is the top level    */
+/* executor which is an infinite loop.  The structure is similar to    */
+/* error.                                                              */
+
+extern char _sobuf[];
+extern lispval reborn;
+extern int rlevel;
+static int virgin = 0;
+int    Xargc;
+char   **Xargv;
+extern char **environ;
+
+main(argc,argv,arge)
+char **argv,**arge;
+{
+       lispval matom(), Lapply();
+       extern struct frame *errp;
+       extern int holbeg,holend,usehole;
+       extern int *curhbeg;
+       pbuf pb;
+       
+       environ = arge;
+       setbuf(stdout,_sobuf);
+       Xargc = argc;
+       Xargv = argv;
+       virgin = 0;
+       errp = (struct frame *)0;
+       initial();
+
+       errp = Pushframe(F_RESET,nil,nil);
+       switch(retval)
+       {
+       case C_RESET: break;    /* what to do? */
+       case C_INITIAL: break;  /* first time  */
+       }
+
+       for(EVER) {
+               lbot = np = orgnp;
+               rlevel = 0;
+               depth = 0;
+               clearerr(piport = stdin);
+               clearerr(poport = stdout);
+               np++->val = matom("top-level");
+               np++->val = nil;
+               Lapply();
+       }
+}
+
+lispval
+Ntpl()
+{
+       lispval Lread(),Istsrch();
+
+       if (virgin == 0) {
+               fputs((char *)Istsrch(matom("version"))->d.cdr->d.cdr->d.cdr,poport);
+               virgin = 1;
+       }
+       lbot = np;
+       np++->val = P(stdin);
+       np++->val = eofa;
+       while (TRUE)
+               {
+               fputs("\n-> ",stdout);
+               dmpport(stdout);
+               vtemp = Lread();
+               if(vtemp == eofa) exit(0);
+               printr(eval(vtemp),stdout);
+               }
+       }
+
+/* franzexit :: give up the ghost
+ * this function is called whenever one decides to kill this process. 
+ * We clean up a bit then call then standard exit routine.  C code 
+ * in franz should never call exit() directly.
+ */
+franzexit(code)
+{
+       extern int fvirgin;
+       extern char *stabf;
+       if(!fvirgin) unlink(stabf);     /* give up any /tmp symbol tables */
+       exit(code);
+/* is this something special?? _cleanup();
+ *                             proflush();
+ *                             _exit(code);
+ */
+                               
+}
diff --git a/usr/src/ucb/lisp/franz/pbignum.c b/usr/src/ucb/lisp/franz/pbignum.c
new file mode 100644 (file)
index 0000000..e2a150f
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: pbignum.c,v 1.3 83/09/12 14:17:59 sklower Exp $";
+#endif
+
+/*                                     -[Sat Jan 29 13:30:47 1983 by jkf]-
+ *     pbignum.c                       $Locker:  $
+ * print a bignum
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+
+pbignum(current, useport)
+register lispval current;
+register FILE *useport;
+{
+       long  *top, *bot, *work, negflag = 0;
+       char *alloca();
+       register int *digitp;
+       Keepxs();
+
+       /* copy bignum onto stack */
+       top = (sp()) - 1;
+       do {
+               stack(current->s.I);
+       } while(current = current->s.CDR);
+
+       bot = sp();
+       if (top==bot) {
+               fprintf(useport,"%d",*bot);
+               Freexs();
+               return;
+       }
+
+       /* save space for printed digits*/
+       work = (int *)alloca((top-bot)*2*sizeof(int));
+       if( *bot < 0) {
+               negflag = 1;
+               dsneg(top,bot);
+       }
+
+       /* figure out nine digits at a time by destructive division*/
+       for(digitp = work; bot <= top; digitp++) {
+               *digitp = dodiv(top,bot);
+               if(*bot==0) bot += 1;
+       }
+       
+       /* print them out */
+
+       if(negflag) putc('-',useport);
+       fprintf(useport,"%d",*--digitp);
+       while ( digitp > work) fprintf(useport,"%.09d",*--digitp);
+       Freexs();
+}
diff --git a/usr/src/ucb/lisp/franz/rlc.c b/usr/src/ucb/lisp/franz/rlc.c
new file mode 100644 (file)
index 0000000..915c55a
--- /dev/null
@@ -0,0 +1,33 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: rlc.c,v 1.2 83/08/30 12:31:39 sklower Exp $";
+#endif
+
+/*                                     -[Sat Jan 29 13:32:26 1983 by jkf]-
+ *     rlc.c                           $Locker:  $
+ * relocator for data space 
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#define TRUE 1
+#include "h/global.h"
+#ifdef os_4_2
+#define brk _brk
+#endif
+extern char holend[], end[];
+extern int usehole;
+extern char *curhbeg;
+
+rlc()
+{
+       char *cp, *dp;
+       
+       brk(end);
+       dp = holend;
+       cp = dp - HOLE;
+       while (dp < end)
+               *dp++ = *cp++;
+       curhbeg = holend - HOLE;        /* set up the hole */
+       usehole = TRUE;
+}
diff --git a/usr/src/ucb/lisp/franz/subbig.c b/usr/src/ucb/lisp/franz/subbig.c
new file mode 100644 (file)
index 0000000..be1b129
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: subbig.c,v 1.2 83/09/12 14:17:31 sklower Exp $";
+#endif
+
+/*                                     -[Sat Jan 29 13:36:05 1983 by jkf]-
+ *     subbig.c                        $Locker:  $
+ * bignum subtraction
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+
+/*
+ * subbig -- subtract one bignum from another.
+ *
+ * What this does is it negates each coefficient of a copy of the bignum
+ * which is just pushed on the stack for convenience.  This may give rise
+ * to a bignum which is not in canonical form, but is nonetheless a repre
+ * sentation of a bignum.  Addbig then adds it to a bignum, and produces
+ * a result in canonical form.
+ */
+lispval
+subbig(pos,neg)
+lispval pos, neg;
+{
+       register lispval work;
+       lispval adbig();
+       register long *mysp = sp() - 2;
+       register long *ersatz = mysp;
+       Keepxs();
+
+       for(work = neg; work!=0; work = work->s.CDR) {
+               stack((long)(mysp -= 2));
+               stack(-work->i);
+       }
+       mysp[3] = 0;
+       work = (adbig(pos,(lispval)ersatz));
+       Freexs();
+       return(work);
+}
diff --git a/usr/src/ucb/lisp/franz/sysat.c b/usr/src/ucb/lisp/franz/sysat.c
new file mode 100644 (file)
index 0000000..fb45ab7
--- /dev/null
@@ -0,0 +1,753 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: sysat.c,v 1.15 83/09/04 10:17:54 jkf Exp $";
+#endif
+
+/*                                     -[Sun Sep  4 08:56:49 1983 by jkf]-
+ *     sysat.c                         $Locker:  $
+ * startup data structure creation
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+#include "lfuncs.h"
+#define MK(x,y,z) mfun(x,y,z)
+#define FIDDLE(z,b,c,y) z->a.clb=newdot(); (z->a.clb->d.car=newint())->i=b->i; \
+       z->a.clb->d.cdr=newdot(); (z->a.clb->d.cdr->d.car=newint())->i=c->i; \
+       z->a.clb->d.cdr->d.cdr=newdot(); (z->a.clb->d.cdr->d.cdr->d.car=newint())->i=y; \
+       b = z->a.clb->d.car; c = z->a.clb->d.cdr->d.car; \
+       copval(z,z->a.clb); z->a.clb = nil;
+
+#define cforget(x) protect(x); Lforget(); unprot();
+
+/*  The following array serves as the temporary counters of the items  */
+/*  and pages used in each space.                                      */
+
+long int tint[2*NUMSPACES];
+
+extern int tgcthresh; 
+extern int initflag;   /*  starts off TRUE to indicate unsafe to gc  */
+
+extern int *beginsweep;        /* place for garbage collector to begin sweeping */
+extern int page_limit;  /* begin warning messages about running out of space */
+extern char purepage[]; /* which pages should not be swept by gc */
+extern int ttsize;     /* need to know how much of pagetable to set to other */
+
+extern lispval Iaddstat(), Isstatus();
+
+makevals()
+       {
+       int i;
+       lispval temp;
+
+       /*  system list structure and atoms are initialized.  */
+
+       /*  Before any lisp data can be created, the space usage */
+       /*  counters must be set up, temporarily in array tint.  */
+
+       atom_items = (lispval) &tint[0];
+       atom_pages = (lispval) &tint[1];
+       str_items = (lispval) &tint[2];
+       str_pages = (lispval) &tint[3];
+       int_items = (lispval) &tint[4];
+       int_pages = (lispval) &tint[5];
+       dtpr_items = (lispval) &tint[6];
+       dtpr_pages = (lispval) &tint[7];
+       doub_items = (lispval) &tint[8];
+       doub_pages = (lispval) &tint[9];
+       sdot_items = (lispval) &tint[10];
+       sdot_pages = (lispval) &tint[11];
+       array_items = (lispval) &tint[12];
+       array_pages = (lispval) &tint[13];
+       val_items = (lispval) &tint[14];
+       val_pages = (lispval) &tint[15];
+       funct_items = (lispval) &tint[16];
+       funct_pages = (lispval) &tint[17];
+
+       for (i=0; i < 7; i++)
+       {
+               hunk_pages[i] = (lispval) &tint[18+i*2];
+               hunk_items[i] = (lispval) &tint[19+i*2];
+       }
+
+       vect_items = (lispval) &tint[34];
+       vecti_items = (lispval) &tint[35];
+       vect_pages = (lispval) &tint[36];
+       vecti_pages = (lispval) &tint[37];
+       other_items = (lispval) &tint[38];
+       other_pages = (lispval) &tint[39];
+       
+       /*  This also applies to the garbage collection threshhold  */
+
+       gcthresh = (lispval) &tgcthresh;
+
+       /*  Now we commence constructing system lisp structures.  */
+
+       /*  nil is a special case, constructed especially at location zero  */
+
+       hasht[hashfcn("nil")] = (struct atom *)nil;
+
+
+       /* allocate space for namestack and bindstack first
+        * then set up beginsweep variable so that the sweeper will
+        * ignore these `always in use' pages
+        */
+
+       lbot = orgnp = np = ((struct argent *)csegment(VALUE,NAMESIZE,FALSE));
+       orgbnp = bnp = ((struct nament *)csegment(DTPR,NAMESIZE,FALSE));
+       /* since these dtpr pages will not be swept, we don't want them
+        * to show up in count of dtpr pages allocated or it will confuse
+        * gcafter when it tries to determine how much space is free
+        */
+       dtpr_pages->i = 0;
+       beginsweep = (int *) xsbrk(0);
+
+       /*
+        *  patching up info in type and pure tables
+        */
+       for(i=((int)beginsweep)>>9; i < ttsize; i++) (typetable+1)[i] = OTHER;
+       purepage[((int)np)>>9] = 1;  /* Mark these as non-gc'd arrays */
+       purepage[((int)bnp)>>9] = 1;
+
+       /*
+        * Names of various spaces and things
+        */
+
+       atom_name = matom("symbol");
+       str_name = matom("string");
+       int_name = matom("fixnum");
+       dtpr_name = matom("list");
+       doub_name = matom("flonum");
+       sdot_name = matom("bignum");
+       array_name = matom("array");
+       val_name = matom("value");
+       funct_name = matom("binary");
+       port_name = matom("port");              /* not really a space */
+       vect_name = matom("vector");
+       vecti_name = matom("vectori");
+       other_name = matom("other");
+
+       {
+           char name[6], *strcpy();
+
+           strcpy(name, "hunk0");
+           for (i=0; i< 7; i++) {
+               hunk_name[i] = matom(name);
+               name[4]++;
+           }
+       }
+       
+       /*  set up the name stack as an array of pointers */
+       nplim = orgnp+NAMESIZE-6*NAMINC;
+       temp = matom("namestack");
+       nstack = temp->a.fnbnd = newarray();
+       nstack->ar.data = (char *) (np);
+       (nstack->ar.length = newint())->i = NAMESIZE;
+       (nstack->ar.delta = newint())->i = sizeof(struct argent);
+       Vnogbar = matom("unmarked_array");
+       /* marking of the namestack will be done explicitly in gc1 */
+       (nstack->ar.aux = newdot())->d.car = Vnogbar; 
+                                               
+
+       /* set up the binding stack as an array of dotted pairs */
+
+       bnplim = orgbnp+NAMESIZE-5;
+       temp = matom("bindstack");
+       bstack = temp->a.fnbnd = newarray();
+       bstack->ar.data = (char *) (bnp);
+       (bstack->ar.length = newint())->i = NAMESIZE;
+       (bstack->ar.delta = newint())->i = sizeof(struct nament);
+       /* marking of the bindstack will be done explicitly in gc1 */
+       (bstack->ar.aux = newdot())->d.car = Vnogbar; 
+
+       /* more atoms */
+
+       tatom = matom("t");
+       tatom->a.clb = tatom;
+       lambda = matom("lambda");
+       nlambda = matom("nlambda");
+       macro = matom("macro");
+       ibase = matom("ibase");         /* base for input conversion */
+       ibase->a.clb = inewint(10);
+       (matom("base"))->a.clb = ibase->a.clb;
+       fclosure = matom("fclosure");
+       clos_marker = matom("int:closure-marker");
+       Vpbv = matom("value-structure-argument");
+       rsetatom = matom("*rset");
+       rsetatom->a.clb = nil;
+       Vsubrou = matom("subroutine");
+       Vpiport = matom("piport");
+       Vpiport->a.clb = P(piport = stdin);     /* standard input */
+       Vpoport = matom("poport");
+       Vpoport->a.clb = P(poport = stdout);    /* stand. output */
+       matom("errport")->a.clb = (P(errport = stderr));/* stand. err. */
+       ioname[PN(stdin)]  = (lispval) pinewstr("$stdin");
+       ioname[PN(stdout)] = (lispval) pinewstr("$stdout");
+       ioname[PN(stderr)] = (lispval) pinewstr("$stderr");
+       matom("Standard-Input")->a.clb = Vpiport->a.clb;
+       matom("Standard-Output")->a.clb = Vpoport->a.clb;
+       matom("Standard-Error")->a.clb = P(errport);
+       (Vreadtable = matom("readtable"))->a.clb  = Imkrtab(0);
+       strtab = Imkrtab(0);
+       Vptport = matom("ptport");
+       Vptport->a.clb = nil;                           /* protocal port */
+
+       Vcntlw = matom("^w");   /* when non nil, inhibits output to term */
+       Vcntlw->a.clb = nil;
+
+       Vldprt = matom("$ldprint");     
+                       /* when nil, inhibits printing of fasl/autoload   */
+                                               /* cfasl messages to term */
+       Vldprt->a.clb = tatom;
+
+       Vprinlevel = matom("prinlevel");        /* printer recursion count */
+       Vprinlevel->a.clb = nil;                /* infinite recursion */
+
+       Vprinlength = matom("prinlength");      /* printer element count */
+       Vprinlength->a.clb = nil;               /* infinite elements */
+
+       Vfloatformat = matom("float-format");
+       Vfloatformat->a.clb = (lispval) pinewstr("%.16g");
+
+       Verdepth = matom("Error-Depth");
+       Verdepth->a.clb = inewint(0);           /* depth of error */
+
+       Vpurcopylits = matom("$purcopylits");
+       Vpurcopylits->a.clb = tatom;            /* tells fasl to purcopy
+                                                *  literals it reads
+                                                */
+       Vdisplacemacros = matom("displace-macros");
+        Vdisplacemacros->a.clb = nil;          /* replace macros calls
+                                                * with their expanded forms
+                                                */
+
+       Vprintsym = matom("print");
+       
+       atom_buffer = (lispval) strbuf;
+       Vlibdir = matom("lisp-library-directory");
+       Vlibdir->a.clb = matom("/usr/lib/lisp");
+       /*  The following atoms are used as tokens by the reader  */
+
+       perda = matom(".");
+       lpara = matom("(");
+       rpara = matom(")");
+       lbkta = matom("[");
+       rbkta = matom("]");
+       snqta = matom("'");
+       exclpa = matom("!");
+
+
+       (Eofa = matom("eof"))->a.clb = eofa;
+       cara = MK("car",Lcar,lambda);
+       cdra = MK("cdr",Lcdr,lambda);
+
+       /*  The following few atoms have values the reader tokens.  */
+       /*  Perhaps this is a kludge which should be abandoned.  */
+       /*  On the other hand, perhaps it is an inspiration.    */
+
+       matom("perd")->a.clb = perda;
+       matom("lpar")->a.clb = lpara;
+       matom("rpar")->a.clb = rpara;
+       matom("lbkt")->a.clb = lbkta;
+       matom("rbkt")->a.clb = rbkta;
+
+       noptop = matom("noptop");
+
+       /*  atoms used in connection with comments.  */
+
+       commta = matom("comment");
+       rcomms = matom("readcomments");
+
+       /*  the following atoms are used for lexprs */
+
+       lexpr_atom = matom("last lexpr binding\7");
+       lexpr = matom("lexpr");
+
+       /* the following atom is used to reference the bind stack for eval */
+       bptr_atom = matom("eval1 binding pointer\7");
+       bptr_atom->a.clb = nil;
+
+       /* the following atoms are used for evalhook hackery */
+       evalhatom = matom("evalhook");
+       evalhatom->a.clb = nil;
+       evalhcallsw = FALSE;
+
+       funhatom = matom("funcallhook");
+       funhatom->a.clb = nil;
+       funhcallsw = FALSE;
+
+       Vevalframe = matom("evalframe");
+
+       sysa = matom("sys");
+       plima = matom("pagelimit");     /*  max number of pages  */
+       Veval = MK("eval",Leval1,lambda);
+
+
+       MK("asin",Lasin,lambda);
+       MK("acos",Lacos,lambda);
+       MK("atan",Latan,lambda);
+       MK("cos",Lcos,lambda);
+       MK("sin",Lsin,lambda);
+       MK("sqrt",Lsqrt,lambda);
+       MK("exp",Lexp,lambda);
+       MK("log",Llog,lambda);
+       MK("lsh",Llsh,lambda);
+       MK("bignum-leftshift",Lbiglsh,lambda);
+       MK("sticky-bignum-leftshift",Lsbiglsh,lambda);
+       MK("frexp",Lfrexp,lambda);
+       MK("rot",Lrot,lambda);
+       MK("random",Lrandom,lambda);
+       MK("atom",Latom,lambda);
+       MK("apply",Lapply,lambda);
+       MK("funcall",Lfuncal,lambda);
+       MK("lexpr-funcall",Llexfun,lambda);
+       MK("return",Lreturn,lambda);
+/*     MK("cont",Lreturn,lambda);  */
+       MK("cons",Lcons,lambda);
+       MK("scons",Lscons,lambda);
+       MK("bignum-to-list",Lbigtol,lambda);
+       MK("cadr",Lcadr,lambda);
+       MK("caar",Lcaar,lambda);
+       MK("cddr",Lc02r,lambda);
+       MK("caddr",Lc12r,lambda);
+       MK("cdddr",Lc03r,lambda);
+       MK("cadddr",Lc13r,lambda);
+       MK("cddddr",Lc04r,lambda);
+       MK("caddddr",Lc14r,lambda);
+       MK("nthelem",Lnthelem,lambda);
+       MK("eq",Leq,lambda);
+       MK("equal",Lequal,lambda);
+/**    MK("zqual",Zequal,lambda);      */
+       MK("numberp",Lnumberp,lambda);
+       MK("dtpr",Ldtpr,lambda);
+       MK("bcdp",Lbcdp,lambda);
+       MK("portp",Lportp,lambda);
+       MK("arrayp",Larrayp,lambda);
+       MK("valuep",Lvaluep,lambda);
+       MK("get_pname",Lpname,lambda);
+       MK("ptr",Lptr,lambda);
+       MK("arrayref",Larrayref,lambda);
+       MK("marray",Lmarray,lambda);
+       MK("getlength",Lgetl,lambda);
+       MK("putlength",Lputl,lambda);
+       MK("getaccess",Lgeta,lambda);
+       MK("putaccess",Lputa,lambda);
+       MK("getdelta",Lgetdel,lambda);
+       MK("putdelta",Lputdel,lambda);
+       MK("getaux",Lgetaux,lambda);
+       MK("putaux",Lputaux,lambda);
+       MK("getdata",Lgetdata,lambda);
+       MK("putdata",Lputdata,lambda);
+       MK("mfunction",Lmfunction,lambda);
+       MK("getentry",Lgetentry,lambda);
+       MK("getdisc",Lgetdisc,lambda);
+       MK("putdisc",Lputdisc,lambda);
+       MK("segment",Lsegment,lambda);
+       MK("rplaca",Lrplaca,lambda);
+       MK("rplacd",Lrplacd,lambda);
+       MK("set",Lset,lambda);
+       MK("replace",Lreplace,lambda);
+       MK("infile",Linfile,lambda);
+       MK("outfile",Loutfile,lambda);
+       MK("terpr",Lterpr,lambda);
+       MK("print",Lprint,lambda);
+       MK("close",Lclose,lambda);
+       MK("patom",Lpatom,lambda);
+       MK("pntlen",Lpntlen,lambda);
+       MK("read",Lread,lambda);
+       MK("ratom",Lratom,lambda);
+       MK("readc",Lreadc,lambda);
+       MK("truename",Ltruename,lambda);
+       MK("implode",Limplode,lambda);
+       MK("maknam",Lmaknam,lambda);
+       MK("deref",Lderef,lambda);
+       MK("concat",Lconcat,lambda);
+       MK("uconcat",Luconcat,lambda);
+       MK("putprop",Lputprop,lambda);
+       MK("monitor",Lmonitor,lambda);
+       MK("get",Lget,lambda);
+       MK("getd",Lgetd,lambda);
+       MK("putd",Lputd,lambda);
+       MK("prog",Nprog,nlambda);
+       quota = MK("quote",Nquote,nlambda);
+       MK("function",Nfunction,nlambda);
+       MK("go",Ngo,nlambda);
+       MK("*catch",Ncatch,nlambda);
+       MK("errset",Nerrset,nlambda);
+       MK("status",Nstatus,nlambda);
+       MK("sstatus",Nsstatus,nlambda);
+       MK("err-with-message",Lerr,lambda);
+       MK("*throw",Nthrow,lambda);     /* this is a lambda now !! */
+       reseta = MK("reset",Nreset,nlambda);
+       MK("break",Nbreak,nlambda);
+       MK("exit",Lexit,lambda);
+       MK("def",Ndef,nlambda);
+       MK("null",Lnull,lambda);
+       /* debugging, remove when done */
+       { lispval Lframedump(); 
+         MK("framedump",Lframedump,lambda);
+       }
+       MK("and",Nand,nlambda);
+       MK("or",Nor,nlambda);
+       MK("setq",Nsetq,nlambda);
+       MK("cond",Ncond,nlambda);
+       MK("list",Llist,lambda);
+       MK("load",Lload,lambda);
+       MK("nwritn",Lnwritn,lambda);
+       MK("*process",Lprocess,lambda); /*  execute a shell command  */
+       MK("allocate",Lalloc,lambda);   /*  allocate a page  */
+       MK("sizeof",Lsizeof,lambda);    /*  size of one item of a data type  */
+       MK("dumplisp",Ndumplisp,nlambda);       /*  NEW save the world  */
+       MK("top-level",Ntpl,nlambda);   /*  top level eval-print read loop  */
+       startup = matom("startup");     /*  used by save and restore  */
+       MK("mapcar",Lmapcar,lambda);
+       MK("maplist",Lmaplist,lambda);
+       MK("mapcan",Lmapcan,lambda);
+       MK("mapcon",Lmapcon,lambda);
+       MK("assq",Lassq,lambda);
+       MK("mapc",Lmapc,lambda);
+       MK("map",Lmap,lambda);
+       MK("flatc",Lflatsi,lambda);
+       MK("alphalessp",Lalfalp,lambda);
+       MK("drain",Ldrain,lambda);
+       MK("killcopy",Lkilcopy,lambda); /*  forks aand aborts for adb */
+       MK("opval",Lopval,lambda);      /*  sets and retrieves system variables  */
+       MK("ncons",Lncons,lambda);
+       sysa = matom("sys");    /*  sys indicator for system variables  */
+       MK("remob",Lforget,lambda);     /*  function to take atom out of hash table  */
+       splice = matom("splicing");
+       MK("not",Lnull,lambda);
+       MK("plus",Ladd,lambda);
+       MK("add",Ladd,lambda);
+       MK("times",Ltimes,lambda);
+       MK("difference",Lsub,lambda);
+       MK("quotient",Lquo,lambda);
+       MK("+",Lfp,lambda);
+       MK("-",Lfm,lambda);
+       MK("*",Lft,lambda);
+       MK("/",Lfd,lambda);
+       MK("1+",Lfadd1,lambda);
+       MK("1-",Lfsub1,lambda);
+       MK("^",Lfexpt,lambda);
+       MK("double-to-float",Ldbtofl,lambda);
+       MK("float-to-double",Lfltodb,lambda);
+       MK("<",Lflessp,lambda);
+       MK("mod",Lmod,lambda);
+       MK("minus",Lminus,lambda);
+       MK("absval",Labsval,lambda);
+       MK("add1",Ladd1,lambda);
+       MK("sub1",Lsub1,lambda);
+       MK("greaterp",Lgreaterp,lambda);
+       MK("lessp",Llessp,lambda);
+       MK("any-zerop",Lzerop,lambda);   /* used when bignum arg possible */
+       MK("zerop",Lzerop,lambda);
+       MK("minusp",Lnegp,lambda);
+       MK("onep",Lonep,lambda);
+       MK("sum",Ladd,lambda);
+       MK("product",Ltimes,lambda);
+       MK("do",Ndo,nlambda);
+       MK("progv",Nprogv,nlambda);
+       MK("progn",Nprogn,nlambda);
+       MK("prog2",Nprog2,nlambda);
+       MK("oblist",Loblist,lambda);
+       MK("baktrace",Lbaktrace,lambda);
+       MK("tyi",Ltyi,lambda);
+       MK("tyipeek",Ltyipeek,lambda);
+       MK("untyi",Luntyi,lambda);
+       MK("tyo",Ltyo,lambda);
+       MK("termcapinit",Ltci,lambda);
+       MK("termcapexe",Ltcx,lambda);
+       MK("int:setsyntax",Lsetsyn,lambda);     /* an internal function */
+       MK("int:getsyntax",Lgetsyntax,lambda);
+       MK("int:showstack",LIshowstack,lambda);
+       MK("int:franz-call",LIfranzcall,lambda);
+       MK("makereadtable",Lmakertbl,lambda);
+       MK("zapline",Lzapline,lambda);
+       MK("aexplode",Lexplda,lambda);
+       MK("aexplodec",Lexpldc,lambda);
+       MK("aexploden",Lexpldn,lambda);
+       MK("hashtabstat",Lhashst,lambda);
+#ifdef METER
+       MK("gcstat",Lgcstat,lambda);
+#endif
+       MK("argv",Largv,lambda);
+       MK("arg",Larg,lambda);
+       MK("setarg",Lsetarg,lambda);
+       MK("showstack",Lshostk,lambda);
+       MK("freturn",Lfretn,lambda);
+       MK("*rset",Lrset,lambda);
+       MK("eval1",Leval1,lambda);
+       MK("evalframe",Levalf,lambda);
+       MK("evalhook",Levalhook,lambda);
+       MK("funcallhook",Lfunhook,lambda);
+       MK("int:fclosure-stack-stuff",LIfss,lambda);
+       MK("resetio",Nresetio,nlambda);
+       MK("chdir",Lchdir,lambda);
+       MK("ascii",Lascii,lambda);
+       MK("boole",Lboole,lambda);
+       MK("type",Ltype,lambda);        /* returns type-name of argument */
+       MK("fix",Lfix,lambda);
+       MK("float",Lfloat,lambda);
+       MK("fact",Lfact,lambda);
+       MK("cpy1",Lcpy1,lambda);
+       MK("Divide",LDivide,lambda);
+       MK("Emuldiv",LEmuldiv,lambda);
+       MK("readlist",Lreadli,lambda);
+       MK("plist",Lplist,lambda);      /* gives the plist of an atom */
+       MK("setplist",Lsetpli,lambda);  /* get plist of an atom  */
+       MK("eval-when",Nevwhen,nlambda);
+       MK("syscall",Lsyscall,lambda);
+       MK("intern",Lintern,lambda);
+       MK("ptime",Lptime,lambda);      /* return process user time */
+       MK("fork",Lfork,lambda);        /* turn on fork and wait */
+       MK("wait",Lwait,lambda);
+/*     MK("pipe",Lpipe,lambda);        */
+/*     MK("fdopen",Lfdopen,lambda); */
+       MK("exece",Lexece,lambda);
+       MK("gensym",Lgensym,lambda);
+       MK("remprop",Lremprop,lambda);
+       MK("bcdad",Lbcdad,lambda);
+       MK("symbolp",Lsymbolp,lambda);
+       MK("stringp",Lstringp,lambda);
+       MK("rematom",Lrematom,lambda);
+/**    MK("prname",Lprname,lambda);    */
+       MK("getenv",Lgetenv,lambda);
+       MK("I-throw-err",Lctcherr,lambda); /* directly force a throw or error */
+       MK("makunbound",Lmakunb,lambda);
+       MK("haipart",Lhaipar,lambda);
+       MK("haulong",Lhau,lambda);
+       MK("signal",Lsignal,lambda);
+       MK("fasl",Lfasl,lambda);        /* NEW - new fasl loader */
+       MK("cfasl",Lcfasl,lambda);      /* read in compiled C file */
+       MK("getaddress",Lgetaddress,lambda);
+                                       /* bind symbols without doing cfasl */
+       MK("removeaddress",Lrmadd,lambda);      /* unbind symbols    */
+       MK("boundp",Lboundp,lambda);    /* tells if an atom is bound */
+       MK("fake",Lfake,lambda);        /* makes a fake lisp pointer */
+/***   MK("od",Lod,lambda);            /* dumps info */
+       MK("maknum",Lmaknum,lambda);    /* converts a pointer to an integer */
+       MK("*mod",LstarMod,lambda);             /* return fixnum modulus */
+       MK("*invmod",Lstarinvmod,lambda);       /* return fixnum modulus ^-1 */
+
+       MK("fseek",Lfseek,lambda);      /* seek to a specific byte in a file */
+       MK("fileopen", Lfileopen, lambda);
+                                       /* open a file for read/write/append*/
+
+       MK("pv%",Lpolyev,lambda);       /* polynomial evaluation instruction*/
+       MK("cprintf",Lcprintf,lambda);  /* formatted print                  */
+       MK("sprintf",Lsprintf,lambda);  /* formatted print to string        */
+       MK("copyint*",Lcopyint,lambda); /* copyint*  */
+       MK("purcopy",Lpurcopy,lambda);  /* pure copy */
+       MK("purep",Lpurep,lambda);      /* check if pure */
+       MK("int:memreport",LImemory,lambda); /* dump memory stats */
+
+/*
+ * Hunk stuff
+ */
+
+       MK("*makhunk",LMakhunk,lambda);         /* special hunk creater */
+       MK("hunkp",Lhunkp,lambda);              /* test a hunk */
+       MK("cxr",Lcxr,lambda);                  /* cxr of a hunk */
+       MK("rplacx",Lrplacx,lambda);            /* replace element of a hunk */
+       MK("*rplacx",Lstarrpx,lambda);          /* rplacx used by hunk */
+       MK("hunksize",Lhunksize,lambda);        /* size of a hunk */
+       MK("hunk-to-list",Lhtol,lambda);        /* hunk to list */
+       
+       /* vector stuff */
+       MK("new-vector",Lnvec,lambda);
+       MK("new-vectori-byte",Lnvecb,lambda);
+       MK("new-vectori-word",Lnvecw,lambda);
+       MK("new-vectori-long",Lnvecl,lambda);
+       MK("vectorp",Lvectorp,lambda);
+       MK("vectorip",Lpvp,lambda);
+       MK("int:vref",LIvref,lambda);
+       MK("int:vset",LIvset,lambda);
+       MK("int:vsize",LIvsize,lambda);
+       MK("vsetprop",Lvsp,lambda);
+       MK("vprop",Lvprop,lambda);
+
+       MK("probef",Lprobef,lambda);    /* test file existance */
+       MK("substring",Lsubstring,lambda);
+       MK("substringn",Lsstrn,lambda);
+       MK("time-string",Ltimestr,lambda);
+       odform = matom("odformat");     /* format for printf's used in od */
+       rdrsdot = newsdot();            /* used in io conversions of bignums */
+       rdrsdot2 = newsdot();           /* used in io conversions of bignums */
+       rdrint = newint();              /* used as a temporary integer */
+       (nilplist = newdot())->d.cdr = newdot();
+                                       /* used as property list for nil,
+                                          since nil will eventually be put at
+                                          0 (consequently in text and not
+                                          writable) */
+
+       /* error variables */
+       (Vererr = matom("ER%err"))->a.clb = nil;
+       (Vertpl = matom("ER%tpl"))->a.clb = nil;
+       (Verall = matom("ER%all"))->a.clb = nil;
+       (Vermisc = matom("ER%misc"))->a.clb = nil;
+       (Verbrk = matom("ER%brk"))->a.clb = nil;
+       (Verundef = matom("ER%undef"))->a.clb = nil;
+       (Vlerall = newdot())->d.car = Verall;   /* list (ER%all) */
+       (Veruwpt = matom("ER%unwind-protect"))->a.clb = nil;
+       (Verrset = matom("errset"))->a.clb = nil;
+
+
+       /* set up the initial status list */
+
+       stlist = nil;                   /* initially nil */
+       {
+           lispval feature, dom;
+           Iaddstat(matom("features"),ST_READ,ST_NO,nil);
+           Iaddstat(feature = matom("feature"),ST_FEATR,ST_FEATW,nil);
+           Isstatus(feature,matom("franz"));
+           Isstatus(feature,matom("Franz"));
+           Isstatus(feature,matom(OS));
+           Isstatus(feature,matom("string"));
+           Isstatus(feature,dom = matom(DOMAIN));
+           Iaddstat(matom("domain"),ST_READ,ST_NO,dom);
+           Isstatus(feature,matom(MACHINE));
+#ifdef PORTABLE
+           Isstatus(feature,matom("portable"));
+#endif
+#ifdef unisoft
+           Isstatus(feature,matom("unisoft"));
+#endif
+#ifdef sun
+           Isstatus(feature,matom("sun"));
+#endif
+#if os_4_1c | os_4_2
+           Isstatus(feature,matom("long-filenames"));
+#endif
+       }
+       Iaddstat(matom("nofeature"),ST_NFETR,ST_NFETW,nil);
+       Iaddstat(matom("syntax"),ST_SYNT,ST_NO,nil);
+       Iaddstat(matom("uctolc"),ST_READ,ST_TOLC,nil);
+       Iaddstat(matom("dumpcore"),ST_READ,ST_CORE,nil);
+       Isstatus(matom("dumpcore"),nil);        /*set up signals*/
+
+       Iaddstat(matom("chainatom"),ST_RINTB,ST_INTB,inewint(0));
+       Iaddstat(matom("dumpmode"),ST_DMPR,ST_DMPW,nil);
+       Iaddstat(matom("appendmap"),ST_READ,ST_SET,nil);  /* used by fasl */
+       Iaddstat(matom("debugging"),ST_READ,ST_SET,nil);  
+       Iaddstat(matom("evalhook"),ST_RINTB,ST_INTB,inewint(3));
+       Isstatus(matom("evalhook"),nil); /*evalhook switch off */
+       Iaddstat(matom("bcdtrace"),ST_READ,ST_BCDTR,nil);
+       Iaddstat(matom("ctime"),ST_CTIM,ST_NO,nil);
+       Iaddstat(matom("localtime"),ST_LOCT,ST_NO,nil);
+       Iaddstat(matom("isatty"),ST_ISTTY,ST_NO,nil);
+       Iaddstat(matom("ignoreeof"),ST_READ,ST_SET,nil);
+       Iaddstat(matom("version"),ST_READ,ST_NO,mstr("Franz Lisp, Opus 38"));
+       Iaddstat(matom("automatic-reset"),ST_READ,ST_AUTR,nil);
+       Iaddstat(matom("translink"),ST_READ,ST_TRAN,nil);
+       Isstatus(matom("translink"),nil);               /* turn off tran links */
+       Iaddstat(matom("undeffunc"),ST_UNDEF,ST_NO,nil); /* list undef funcs */
+       Iaddstat(matom("gcstrings"),ST_READ,ST_GCSTR,nil); /* gc strings */
+
+       /* garbage collector things */
+
+       MK("gc",Ngc,nlambda);
+       gcafter = MK("gcafter",Ngcafter,nlambda);       /* garbage collection wind-up */
+       gcport = matom("gcport");       /* port for gc dumping */
+       gccheck = matom("gccheck");     /* flag for checking during gc */
+       gcdis = matom("gcdisable");     /* variable for disabling the gc */
+       gcdis->a.clb = nil;
+       gcload = matom("gcload");       /* option for gc while loading */
+       loading = matom("loading");     /* flag--in loader if = t  */
+       noautot = matom("noautotrace"); /* option to inhibit auto-trace */
+       Vgcprint = matom("$gcprint");   /* if t then pring gc messages */
+       Vgcprint->a.clb = nil;
+       
+       (gcthresh = newint())->i = tgcthresh;
+       gccall1 = newdot();  gccall2 = newdot();  /* used to call gcafter */
+       gccall1->d.car = gcafter;  /* start constructing a form for eval */
+
+       arrayst = mstr("ARRAY");        /* array marker in name stack */
+       bcdst = mstr("BINARY");         /* binary function marker */
+       listst = mstr("INTERPRETED");   /* interpreted function marker */
+       macrost = mstr("MACRO");        /* macro marker */
+       protst = mstr("PROTECTED");     /* protection marker */
+       badst = mstr("BADPTR");         /* bad pointer marker */
+       argst = mstr("ARGST");          /* argument marker */
+       hunkfree = mstr("EMPTY");       /* empty hunk cell value */
+
+       /* type names */
+
+       FIDDLE(atom_name,atom_items,atom_pages,ATOMSPP);
+       FIDDLE(str_name,str_items,str_pages,STRSPP);
+       FIDDLE(other_name,other_items,other_pages,STRSPP);
+       FIDDLE(int_name,int_items,int_pages,INTSPP);
+       FIDDLE(dtpr_name,dtpr_items,dtpr_pages,DTPRSPP);
+       FIDDLE(doub_name,doub_items,doub_pages,DOUBSPP);
+       FIDDLE(sdot_name,sdot_items,sdot_pages,SDOTSPP);
+       FIDDLE(array_name,array_items,array_pages,ARRAYSPP);
+       FIDDLE(val_name,val_items,val_pages,VALSPP);
+       FIDDLE(funct_name,funct_items,funct_pages,BCDSPP);
+
+       FIDDLE(hunk_name[0], hunk_items[0], hunk_pages[0], HUNK2SPP);
+       FIDDLE(hunk_name[1], hunk_items[1], hunk_pages[1], HUNK4SPP);
+       FIDDLE(hunk_name[2], hunk_items[2], hunk_pages[2], HUNK8SPP);
+       FIDDLE(hunk_name[3], hunk_items[3], hunk_pages[3], HUNK16SPP);
+       FIDDLE(hunk_name[4], hunk_items[4], hunk_pages[4], HUNK32SPP);
+       FIDDLE(hunk_name[5], hunk_items[5], hunk_pages[5], HUNK64SPP);
+       FIDDLE(hunk_name[6], hunk_items[6], hunk_pages[6], HUNK128SPP);
+       
+       FIDDLE(vect_name, vect_items, vect_pages, VECTORSPP)
+       FIDDLE(vecti_name, vecti_items, vecti_pages, VECTORSPP)
+
+       (plimit = newint())->i = page_limit;
+       copval(plima,plimit);  /*  default value  */
+
+       /* the following atom is used when reading caar, cdar, etc. */
+
+       xatom = matom("??");
+
+       /*  now it is OK to collect garbage  */
+
+       initflag = FALSE;
+       }
+
+/*  matom("name")  ******************************************************/
+/*                                                                     */
+/*  simulates an atom being read in from the reader and returns a      */
+/*  pointer to it.                                                     */
+/*                                                                     */
+/*  BEWARE:  if an atom becomes "truly worthless" and is collected,    */
+/*  the pointer becomes obsolete.                                      */
+/*                                                                     */
+lispval
+matom(string)
+char *string;
+       {
+       strbuf[0] = 0;
+       strcatn(strbuf,string,STRBLEN-1); /* strcpyn always pads to n */
+       strbuf[STRBLEN-1] = 0;
+       return(getatom(TRUE));
+       }
+
+/*  mstr  ***************************************************************/
+/*                                                                     */
+/*  Makes a string.  Uses matom.                                       */
+/*  Not the most efficient but will do until the string from the code  */
+/*  itself can be used as a lispval.                                   */
+
+lispval mstr(string) char *string;
+       {
+       return((lispval)(pinewstr(string)));
+       }
+
+/*  mfun("name",start)  *************************************************/
+/*                                                                     */
+/*  Same as matom, but entry point to c code is associated with                */
+/*  "name" as function binding.                                                */
+/*  A pointer to the atom is returned.                                 */
+/*                                                                     */
+lispval mfun(string,start,discip) char *string; lispval (*start)(), discip;
+       {
+       lispval v;
+       v = matom(string);
+       v->a.fnbnd = newfunct();
+       v->a.fnbnd->bcd.start = start;
+       v->a.fnbnd->bcd.discipline = discip;
+       return(v);
+       }
diff --git a/usr/src/ucb/lisp/franz/trace.c b/usr/src/ucb/lisp/franz/trace.c
new file mode 100644 (file)
index 0000000..b6a6fed
--- /dev/null
@@ -0,0 +1,140 @@
+#ifndef lint
+static char *rcsid =
+   "$Header: /na/franz/franz/RCS/trace.c,v 1.2 83/08/19 09:50:34 jkf Exp $";
+#endif
+
+/*                                     -[Thu Aug 18 10:08:36 1983 by jkf]-
+ *     trace.c                         $Locker:  $
+ * evalhook evaluator
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+#include "global.h"
+lispval
+Leval1(){
+    register struct nament *bindptr;
+    register lispval handy;
+    if (np-lbot == 2) {        /*if two arguments to eval */
+       if (TYPE((lbot+1)->val) != INT)
+           error("Eval: 2nd arg not legal alist pointer", FALSE);
+       bindptr = orgbnp + (lbot+1)->val->i;
+       if (rsetsw == 0 || rsetatom->a.clb == nil)
+           error("Not in *rsetmode; second arg is useless - eval", TRUE);
+       if (bptr_atom->a.clb != nil)
+           error("WARNING - Nesting 2nd args to eval will give spurious values", TRUE);
+       if (bindptr < orgbnp || bindptr >bnplim)
+           error("Illegal pdl pointer as 2nd arg - eval", FALSE);
+       handy = newdot();
+       handy->d.car = (lispval)bindptr;
+       handy->d.cdr = (lispval)bnp;
+       PUSHDOWN(bptr_atom, handy); 
+       handy = eval(lbot->val);
+       POP;
+       return(handy);
+    } else {   /* normal case - only one arg */
+       chkarg(1,"eval");
+       handy = eval(lbot->val);
+       return(handy);
+    };
+}
+
+lispval
+Levalhook()
+{
+    register lispval handy;
+    register lispval funhval = CNIL;
+
+    switch (np-lbot) 
+    {
+    case 2: break;
+    case 3: funhval = (lbot+2)->val;
+           break;
+    default: argerr("evalhook");
+    }
+
+    /* Don't do this check any longer
+     * if (evalhsw == 0) 
+     *     error("evalhook called before doing sstatus-evalhook", TRUE);
+     * if (rsetsw == 0 || rsetatom->a.clb == nil)
+     *    error("evalhook called while not in *rset mode", TRUE);
+     */
+     
+    if(funhval != CNIL) { PUSHDOWN(funhatom,funhval); }
+
+    PUSHDOWN(evalhatom,(lispval)(lbot+1)->val);
+    /* eval checks evalhcall to see if this is a LISP call to evalhook
+       in which case it avoids call to evalhook function, but clobbers
+       value to nil so recursive calls will check.  */
+    evalhcallsw = TRUE;        
+    handy = eval(lbot->val);
+    POP;
+
+    if(funhval != CNIL) { POP; }
+
+    return(handy);
+}
+
+
+lispval
+Lfunhook()
+{
+    register lispval handy;
+    register lispval evalhval = CNIL;
+    Savestack(2);
+
+
+    switch (np-lbot) 
+    {
+    case 2: break;
+    case 3: evalhval = (lbot+2)->val;
+           break;
+    default: argerr("funcallhook");
+    }
+
+    /* Don't do this check any longer
+     * if (evalhsw == 0) 
+     *     error("funcallhook called before doing sstatus-evalhook", TRUE);
+     *if (rsetsw == 0 || rsetatom->a.clb == nil)
+     *     error("funcallhook called while not in *rset mode", TRUE);
+     */
+     
+    handy = lbot->val;
+    while (TYPE(handy) != DTPR) 
+      handy = errorh1(Vermisc,"funcallhook: first arg must be a list",nil,TRUE,
+                                          0,handy);
+    if(evalhval != CNIL) { PUSHDOWN(evalhatom,evalhval); }
+
+    PUSHDOWN(funhatom,(lispval)(lbot+1)->val);
+    /* funcall checks funcallhcall to see if this is a LISP call to evalhook
+       in which case it avoids call to evalhook function, but clobbers
+       value to nil so recursive calls will check.  */
+    funhcallsw = TRUE; 
+    /*
+     * the first argument to funhook is a list of already evaluated expressions
+     * which we just stack can call funcall on
+     */
+    lbot = np;         /* base of new args */
+    for ( ; handy != nil ; handy = handy->d.cdr)
+    {
+       protect(handy->d.car);
+    }
+    handy = Lfuncal();
+    POP;
+    if(evalhval != CNIL) { POP;  }
+    Restorestack();
+    return(handy);
+}
+
+
+lispval
+Lrset ()
+    {
+    chkarg(1,"rset");
+
+    rsetsw = (lbot->val == nil) ? 0 : 1;
+    rsetatom->a.clb = (lbot->val == nil) ? nil: tatom;
+    evalhcallsw = FALSE;
+    return(lbot->val);
+}
+
diff --git a/usr/src/ucb/lisp/franz/vax/Makefile b/usr/src/ucb/lisp/franz/vax/Makefile
new file mode 100644 (file)
index 0000000..d8d2974
--- /dev/null
@@ -0,0 +1,209 @@
+# 
+# $Header: /na/franz/franz/vax/RCS/Makefile,v 1.10 83/08/23 10:32:46 sklower Exp $
+#
+# $Locker:  $
+#
+#  Franz Lisp C coded kernel 
+#
+#-- Default Paths:
+#  see ../../ReadMe for a explaination of what LibDir and CopyTo mean
+#  D is the directory used for holding intermediate files during 
+#    compilation
+#-- Options:
+#  there is one compile time options which can be set in this file
+#  * do profiling (ala the unix prof(1) command)
+#
+#  The selection of this options is made below
+#  Other options can be selected by editing ../h/config.h or via
+#  ../../lispconf
+#
+LibDir = /usr/lib/lisp
+ObjDir = /usr/ucb
+CopyTo = /dev/null
+Liszt = liszt
+Lisp = lisp
+# if you change this you must recompile rlc.c 
+# (and change the value in ../Makefile)
+#
+HOLE=  2097152 
+
+.DEFAULT: nlisp
+
+MipSrc1= ../low.c ../lowaux.s
+MipSrc2= ../alloc.c ../data.c
+MipSrc3= ../rlc.c
+MipSrc4= ../lisp.c ../eval.c ../eval2.c ../inits.c ../io.c ../error.c \
+        ../sysat.c ../lam1.c ../lam2.c ../lam3.c ../lam4.c ../lam5.c\
+        ../lam6.c  ../lam7.c ../lam8.c ../lam9.c ../lamr.c ../lamp.c \
+        ../fex1.c ../fex2.c ../fex3.c ../fex4.c ../fexr.c\
+        ../fpipe.c \
+        ../subbig.c ../pbignum.c ../divbig.c \
+        ../ffasl.c ../fasl.c \
+        ../trace.c ../evalf.c ../frame.c ../lamgc.c
+
+MipSrc = ${MipSrc1} ${MipSrc2} ${MipSrc3} ${MipSrc4}
+
+MipObj1= ../low.o ../lowaux.o
+MipObj2= ../alloc.o ../data.o
+HoleMipObj2 = ../Salloc.o ../Sdata.o
+HoleMipObj3 = ../rlc.o
+MipObj4= ../lisp.o ../eval.o ../eval2.o ../inits.o ../io.o ../error.o \
+        ../sysat.o ../lam1.o ../lam2.o ../lam3.o ../lam4.o ../lam5.o\
+        ../lam6.o  ../lam7.o ../lam8.o ../lam9.o ../lamr.o ../lamp.o \
+        ../fex1.o ../fex2.o ../fex3.o ../fex4.o ../fexr.o\
+        ../fpipe.o \
+        ../subbig.o ../pbignum.o ../divbig.o \
+        ../ffasl.o ../fasl.o \
+        ../trace.o ../evalf.o ../frame.o ../lamgc.o
+
+#------ Options
+
+#--- profiling selection
+# If the lisp system is to run with profiling, this must be done:
+#  1) remove the # (comment character) from the ProfFlag and
+#     ProfFlag2 definitions below (also do it in ../Makefile)
+#  2) remove all .o files and do a make.
+#
+ProfFlag = # -XP
+ProfFlag2 = # -DPROF
+
+
+# The order of loading of certain files is important.
+# low.o must be first and lowaux second.
+# 
+BottomObj = ${MipObj1}
+
+# Different objects are required depending on whether there is to be
+# a hole between text and data space.
+#
+NoHoleObj = crt0.o ${MipObj2}
+HoleObj   = hcrt0.o ${HoleMipObj2} ${HoleMipObj3}
+
+VaxObj = bigmath.o qfuncl.o vax.o
+
+VaxCSrc = vax.c
+VaxASrc = bigmath.c qfuncl.c crt0.s hcrt0.s
+VaxSrc = ${VaxASrc} ${VaxCSrc}
+
+Eunice = Make.vms Make.uobj rawlisp.unx rawhlisp.unx hole.unx totxtfile.c
+
+AllSrc = Makefile fixmask.c fixpbig.e ${VaxSrc} ${Eunice} ${MipSrc}
+
+
+.SUFFIXES : .c.l
+# on non-ucb systems it might be more
+# polite to use temporary files rather than pipes
+#
+.c.o :
+       @csh -cfe "echo cc -c  $*.c;\
+       rm -f $*.o;\
+       /lib/cpp $< -I../h |\
+       /lib/ccom ${ProfFlag}  | fixmask  |\
+       sed -f fixpbig.e |\
+       /lib/c2 |\
+       as -o $*.o 
+
+.l.o :
+       liszt $< > #resc
+       @echo liszt $< done
+
+# one special case:
+#  add -DPROF if you want to profile the assembler code
+
+qfuncl.o: qfuncl.c
+       cc -I../h -E ${ProfFlag2} qfuncl.c | as -o qfuncl.o
+
+bigmath.o: bigmath.c
+       cc -I../h -E ${ProfFlag2} bigmath.c | as -o bigmath.o
+
+../rlc.o: ../rlc.c 
+       cc -c -O -DHOLE=${HOLE} ../rlc.c 
+       mv rlc.o .. < /dev/null
+
+../low.o: ../low.c
+       cc -I../h -R -c ../low.c  
+       mv low.o .. < /dev/null
+
+../Salloc.o: ../alloc.c
+       (echo "# define HOLE"; cat ../alloc.c) > Salloc.c;\
+       make Salloc.o; mv Salloc.o .. < /dev/null ; rm Salloc.c
+       
+../Sdata.o: ../data.c
+       (echo "# define HOLE ${HOLE}"; cat ../data.c) > Sdata.c;\
+       make Sdata.o; mv Sdata.o .. < /dev/null  ; rm Sdata.c
+
+fixmask: fixmask.c
+       cc -O -o fixmask fixmask.c
+
+# rawlisp is the standard raw lisp system.
+
+rawlisp: fixmask fixpbig.e ${BottomObj} ${NoHoleObj} ${MipObj4} ${VaxObj} 
+       rm -f rawlisp
+       ld -x -o rawlisp -e start ${BottomObj} ${NoHoleObj} \
+                               ${VaxObj} ${MipObj4}  -lm -lc -ltermlib
+       ls -l rawlisp
+
+
+# hlisp is a raw lisp system with a hole between text and data
+
+rawhlisp: fixmask fixpbig.e ${BottomObj} ${HoleObj} ${MipObj4} ${VaxObj} 
+       rm -f rawhlisp
+       ld -x -H ${HOLE} -o rawhlisp -e hstart ${BottomObj}  ${HoleObj} \
+                               ${VaxObj}  ${MipObj4} -lm -lc -ltermlib
+       ls -l rawhlisp
+
+
+clean:
+       rm -f *.o rawlisp nlisp rawhlisp
+
+lint:
+       lint ../h/*.h *.c
+
+tags:  tags ${VaxSrc} ${MipSrc}
+       ctags ../h/*.h ${VaxCSrc} ${MipSrc}
+
+install: nlisp 
+       -rm -f ${ObjDir}/lisp
+       mv nlisp ${ObjDir}/lisp
+       @echo lisp installed
+
+nlisp: rawlisp ${LibDir}
+       -rm -f nlisp
+       (cd ${LibDir} ; make Liszt=${Liszt} required)
+       echo "(progn (setq build:map 'map \
+                          build:lisp-type 'franz \
+                          lisp-library-directory '${LibDir} \
+                          build:dir '${LibDir} \
+                          lisp-object-directory '${ObjDir}) \
+                    (load '${LibDir}/buildlisp)\
+                    (dumplisp nlisp))" | rawlisp
+       ${LibDir}/tackon map nlisp
+       @echo nlisp built
+
+
+donlisp:
+       -rm -f nlisp
+       make LibDir=${LibDir} Liszt=${Liszt} ObjDir=${ObjDir} nlisp
+
+#--- snlisp: create a totally interpreted lisp.
+#      dump as snlisp
+snlisp: rawlisp
+       echo "(progn (setq build:load t         \
+                          build:lisp-type 'franz \
+                          build:dir '${LibDir} \
+                          lisp-object-directory '${ObjDir}\
+                          lisp-library-directory '${LibDir})\
+                    (load '${LibDir}/buildlisp)\
+                    (dumplisp snlisp))" | rawlisp
+
+#--- copysource : copy source files to another directory
+#  called via   make CopyTo=/xx/yyy/zz copysource
+# 
+copysource: ${AllSrc}
+       (tar cf - ${AllSrc} | (cd ${CopyTo} ; tar xf -))
+
+copyobjects: ${AllObj}
+       (tar cf - ${AllObj} | (cd ${CopyTo} ; tar xf -))
+
+scriptcatall: ${AllSrc}
+       @../../scriptcat . franz/vax ${AllSrc} tags
diff --git a/usr/src/ucb/lisp/franz/vax/qfuncl.c b/usr/src/ucb/lisp/franz/vax/qfuncl.c
new file mode 100644 (file)
index 0000000..f0abe3d
--- /dev/null
@@ -0,0 +1,592 @@
+  .asciz "$Header: qfuncl.c,v 1.9 83/09/12 14:05:29 sklower Exp $"
+
+/*                                     -[Mon Mar 21 17:04:58 1983 by jkf]-
+ *     qfuncl.c                                $Locker:  $
+ * lisp to C interface
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+
+/* 
+ * This is written in assembler but must be passed through the C preprocessor
+ * before being assembled.
+ */
+
+#include "ltypes.h"
+#include "config.h"
+
+/* important offsets within data types for atoms */
+#define Atomfnbnd 8
+
+/*  for arrays */
+#define Arrayaccfun 0
+
+#ifdef PROF
+       .set    indx,0
+#define Profile \
+       movab   prbuf+indx,r0 \
+       .set    indx,indx+4 \
+       jsb     mcount
+#define Profile2 \
+       movl   r0,r5 \
+       Profile \
+       movl   r5,r0 
+#else
+#define Profile
+#define Profile2
+#endif
+
+#ifdef PORTABLE
+#define NIL    _nilatom
+#define NP     _np
+#define LBOT   _lbot
+#else
+#define NIL    0
+#define NP     r6
+#define LBOT   r7
+#endif
+
+
+/*   transfer  table linkage routine  */
+
+       .globl  _qlinker
+_qlinker:
+       .word   0xfc0                   # save all possible registers
+       Profile
+       tstl    _exception              # any pending exceptions
+       jeql    noexc
+       tstl    _sigintcnt              # is it because of SIGINT
+       jeql    noexc                   # if not, just leave
+       pushl   $2                      # else push SIGINT
+       calls   $1,_sigcall
+noexc:
+       movl    16(fp),r0               # get return pc
+       addl2   -4(r0),r0               # get pointer to table
+       movl    4(r0),r1                # get atom pointer
+retry:                                 # come here after undef func error
+       movl    Atomfnbnd(r1),r2        # get function binding
+       jleq    nonex                   # if none, leave
+       tstl    _stattab+2*4            # see if linking possible (Strans)
+       jeql    nolink                  # no, it isn't
+       ashl    $-9,r2,r3               # check type of function
+       cmpb    $/**/BCD,_typetable+1[r3]       
+       jeql    linkin                  # bcd, link it in!
+       cmpb    $/**/ARRAY,_typetable+1[r3] # how about array?
+       jeql    doarray                 # yep
+
+
+nolink:
+       pushl   r1                      # non, bcd, call interpreter
+       calls   $1,_Ifuncal
+       ret
+
+/*
+ * handle arrays by pushing the array descriptor on the table and checking
+ * for a bcd array handler
+ */
+doarray:
+       ashl    $-9,Arrayaccfun(r2),r3  # get access function addr shifted
+       cmpb    $/**/BCD,_typetable+1[r3]       # bcd??
+       jneq    nolink                  # no, let funcal handle it
+#ifdef PORTABLE
+       movl    NP,r4
+       movl    r2,(r4)+                # store array header on stack
+       movl    r4,NP
+#else
+       movl    r2,(r6)+                # store array header on stack
+#endif
+       movl    *(r2),r2                # get in func addr
+       jmp     2(r2)                   # jump in beyond calls header
+       
+       
+linkin:        
+       ashl    $-9,4(r2),r3            # check type of function discipline
+       cmpb    $0,_typetable+1[r3]     # is it string?
+       jeql    nolink                  # yes, it is a c call, so dont link in
+       movl    (r2),r2                 # get function addr
+       movl    r2,(r0)                 # put fcn addr in table
+       jmp     2(r2)                   # enter fcn after mask
+
+nonex: pushl   r0                      # preserve table address
+       pushl   r1                      # non existant fcn
+       calls   $1,_Undeff              # call processor
+       movl    r0,r1                   # back in r1
+       movl    (sp)+,r0                # restore table address
+       jbr     retry                   # for the retry.
+
+
+       .globl  __erthrow               # errmessage for uncaught throws
+__erthrow: 
+       .asciz  "Uncaught throw from compiled code"
+
+       .globl _tynames
+_tynames:
+       .long   NIL                             # nothing here
+       .long   _lispsys+20*4                   # str_name
+       .long   _lispsys+21*4                   # atom_name
+       .long   _lispsys+19*4                   # int_name
+       .long   _lispsys+23*4                   # dtpr_name
+       .long   _lispsys+22*4                   # doub_name
+       .long   _lispsys+58*4                   # funct_name
+       .long   _lispsys+103*4                  # port_name
+       .long   _lispsys+47*4                   # array_name
+       .long   NIL                             # nothing here
+       .long   _lispsys+50*4                   # sdot_name
+       .long   _lispsys+53*4                   # val_nam
+       .long   NIL                             # hunk2_nam
+       .long   NIL                             # hunk4_nam
+       .long   NIL                             # hunk8_nam
+       .long   NIL                             # hunk16_nam
+       .long   NIL                             # hunk32_nam
+       .long   NIL                             # hunk64_nam
+       .long   NIL                             # hunk128_nam
+       .long   _lispsys+124*4                  # vector_nam
+       .long   _lispsys+125*4                  # vectori_nam
+
+/*     Quickly allocate small fixnums  */
+
+       .globl  _qnewint
+_qnewint:
+       Profile
+       cmpl    r5,$1024
+       jgeq    alloc
+       cmpl    r5,$-1024
+       jlss    alloc
+       moval   _Fixzero[r5],r0
+       rsb
+alloc:
+       movl    _int_str,r0                     # move next cell addr to r0
+       jlss    callnewi                        # if no space, allocate
+       incl    *_lispsys+24*4                  # inc count of ints
+       movl    (r0),_int_str                   # advance free list
+       movl    r5,(r0)                         # put baby to bed.
+       rsb
+callnewi:
+       pushl   r5
+       calls   $0,_newint
+       movl    (sp)+,(r0)
+       rsb
+
+
+/*  _qoneplus adds one to the boxed fixnum in r0
+ * and returns a boxed fixnum.
+ */
+
+       .globl  _qoneplus
+_qoneplus:
+       Profile2
+       addl3   (r0),$1,r5
+#ifdef PORTABLE
+       movl    r6,NP
+       movl    r6,LBOT
+#endif
+       jmp     _qnewint
+
+/* _qoneminus  subtracts one from the boxes fixnum in r0 and returns a
+ * boxed fixnum
+ */
+       .globl  _qoneminus
+_qoneminus:
+       Profile2
+       subl3   $1,(r0),r5
+#ifdef PORTABLE
+       movl    r6,NP
+       movl    r6,LBOT
+#endif
+       jmp     _qnewint
+
+/*
+ *     _qnewdoub quick allocation of a initialized double (float) cell.
+ *     This entry point is required by the compiler for symmetry reasons.
+ *     Passed to _qnewdoub in r4,r5 is a double precision floating point
+ *     number.  This routine allocates a new cell, initializes it with
+ *     the given value and then returns the cell.
+ */
+
+       .globl  _qnewdoub
+_qnewdoub:
+       Profile
+       movl    _doub_str,r0                    # move next cell addr to r0
+       jlss    callnewd                        # if no space, allocate
+       incl    *_lispsys+30*4                  # inc count of doubs
+       movl    (r0),_doub_str                  # advance free list
+       movq    r4,(r0)                         # put baby to bed.
+       rsb
+
+callnewd:
+       movq    r4,-(sp)                        # stack initial value
+       calls   $0,_newdoub
+       movq    (sp)+,(r0)                      # restore initial value
+       rsb
+
+       .globl  _qcons
+
+/*
+ * quick cons call, the car and cdr are stacked on the namestack
+ * and this function is jsb'ed to.
+ */
+
+_qcons:
+       Profile
+       movl    _dtpr_str,r0                    # move next cell addr to r0
+       jlss    getnew                          # if ran out of space jump
+       incl    *_lispsys+28*4                  # inc count of dtprs
+       movl    (r0),_dtpr_str                  # advance free list
+storit:
+       movl    -(r6),(r0)                      # store in cdr
+       movl    -(r6),4(r0)                     # store in car
+       rsb
+
+getnew:
+#ifdef PORTABLE
+       movl    r6,NP
+       movab   -8(r6),LBOT
+#endif
+       calls   $0,_newdot                      # must gc to get one
+       jbr     storit                          # now initialize it.
+
+/*
+ * Fast equivalent of newdot, entered by jsb
+ */
+
+       .globl  _qnewdot
+_qnewdot:
+       Profile
+       movl    _dtpr_str,r0                    # mov next cell addr t0 r0
+       jlss    mustallo                        # if ran out of space
+       incl    *_lispsys+28*4                  # inc count of dtprs
+       movl    (r0),_dtpr_str                  # advance free list
+       clrq    (r0)
+       rsb
+mustallo:
+       calls   $0,_newdot
+       rsb
+
+/*  prunel  - return a list of dtpr cells to the free list
+ * this is called by the pruneb after it has discarded the top bignum 
+ * the dtpr cells are linked through their cars not their cdrs.
+ * this returns with an rsb
+ *
+ * method of operation: the dtpr list we get is linked by car's so we
+ * go through the list and link it by cdr's, then have the last dtpr
+ * point to the free list and then make the free list begin at the
+ * first dtpr.
+ */
+qprunel:
+       movl    r0,r2                           # remember first dtpr location
+rep:   decl    *_lispsys+28*4                  # decrement used dtpr count
+       movl    4(r0),r1                        # put link value into r1
+       jeql    endoflist                       # if nil, then end of list
+       movl    r1,(r0)                         # repl cdr w/ save val as car
+       movl    r1,r0                           # advance to next dtpr
+       jbr     rep                             # and loop around
+endoflist:
+       movl    _dtpr_str,(r0)                  # make last 1 pnt to free list
+       movl    r2,_dtpr_str                    # & free list begin at 1st 1
+       rsb
+
+/*
+ * qpruneb - called by the arithmetic routines to free an sdot and the dtprs
+ * which hang on it.
+ * called by
+ *     pushl   sdotaddr
+ *     jsb     _qpruneb
+ */
+       .globl  _qpruneb
+_qpruneb:
+       Profile
+       movl    4(sp),r0                                # get address
+       decl    *_lispsys+48*4          # decr count of used sdots
+       movl    _sdot_str,(r0)          # have new sdot point to free list
+       movl    r0,_sdot_str            # start free list at new sdot
+       movl    4(r0),r0                # get address of first dtpr
+       jneq    qprunel                 # if exists, prune it
+       rsb                             # else return.
+
+
+/*
+ * _qprunei     
+ *     called by the arithmetic routines to free a fixnum cell
+ * calling sequence
+ *     pushl   fixnumaddr
+ *     jsb     _qprunei
+ */
+
+       .globl  _qprunei
+_qprunei:
+       Profile
+       movl    4(sp),r0                # get address of fixnum
+       cmpl    r0,$_Lastfix            # is it a small fixnum
+       jleq    skipit                  # if so, leave
+       decl    *_lispsys+24*4          # decr count of used ints
+       movl    _int_str,(r0)           # link the fixnum into the free list
+       movl    r0,_int_str
+skipit:
+       rsb
+
+
+       .globl  _qpopnames
+_qpopnames:                    # equivalent of C-code popnames, entered by jsb.
+       movl    (sp)+,r0        # return address
+       movl    (sp)+,r1        # Lower limit
+       movl    _bnp,r2         # pointer to bind stack entry
+qploop:
+       subl2   $8,r2           # for(; (--r2) > r1;) {
+       cmpl    r2,r1           # test for done
+       jlss    qpdone          
+       movl    (r2),*4(r2)     # r2->atm->a.clb = r2 -> val;
+       brb     qploop          # }
+qpdone:
+       movl    r1,_bnp         # restore bnp
+       jmp     (r0)            # return
+
+/*
+ * _qget : fast get subroutine
+ *  (get 'atom 'ind)
+ * called with -8(r6) equal to the atom
+ *           -4(r6) equal to the indicator
+ * no assumption is made about LBOT
+ * unfortunately, the atom may not in fact be an atom, it may
+ * be a list or nil, which are special cases.
+ * For nil, we grab the nil property list (stored in a special place)
+ * and for lists we punt and call the C routine since it is  most likely
+ * and error and we havent put in error checks yet.
+ */
+
+       .globl  _qget
+_qget:
+       Profile
+       movl    -4(r6),r1       # put indicator in r1
+       movl    -8(r6),r0       # and atom into r0
+       jeql    nilpli          # jump if atom is nil
+       ashl    $-9,r0,r2       # check type
+       cmpb    _typetable+1[r2],$1 # is it a symbol??
+       jneq    notsymb         # nope
+       movl    4(r0),r0        # yes, put prop list in r1 to begin scan
+       jeql    fail            # if no prop list, we lose right away
+lp:    cmpl    r1,4(r0)        # is car of list eq to indicator?
+       jeql    good            # jump if so
+       movl    *(r0),r0        # else cddr down list
+       jneq    lp              # and jump if more list to go.
+
+fail:  subl2   $8,NP           # unstack args
+       rsb                     # return with r0 eq to nil
+
+good:  movl    (r0),r0         # return cadr of list
+       movl    4(r0),r0
+       subl2   $8,NP           #unstack args
+       rsb
+
+nilpli:        movl    _lispsys+64*4,r0 # want nil prop list, get it specially
+       jneq    lp              # and process if anything there
+       subl2   $8,NP           #unstack args
+       rsb                     # else fail
+       
+notsymb:
+#ifdef PORTABLE
+       movl    r6,NP
+       movab   -8(r6),LBOT     # must set up LBOT before calling
+#else
+       movab   -8(r6),LBOT     # must set up LBOT before calling
+#endif
+       calls   $0,_Lget        # not a symbol, call C routine to error check
+       subl2   $8,NP           #unstack args
+       rsb                     # and return what it returned.
+
+/*
+ * _qexarith   exact arithmetic
+ * calculates x=a*b+c  where a,b and c are 32 bit 2's complement integers
+ * whose top two bits must be the same (i.e. the are members of the set
+ * of valid fixnum values for Franz Lisp).  The result, x, will be 64 bits
+ * long but since each of a, b and c had only 31 bits of precision, the
+ * result x only has 62 bits of precision.  The lower 30 bits are returned
+ * in *plo and the high 32 bits are returned in *phi.  If *phi is 0 or -1 then
+ * x doesn't need any more than 31 bits plus sign to describe, so we
+ * place the sign in the high two bits of *plo and return 0 from this
+ * routine.  A non zero return indicates that x requires more than 31 bits
+ * to describe.
+ */
+
+       .globl  _qexarith
+/* qexarith(a,b,c,phi,plo)
+ * int *phi, *plo;
+ */
+_qexarith:
+       emul    4(sp),8(sp),12(sp),r2   #r2 = a*b + c to 64 bits
+       extzv   $0,$30,r2,*20(sp)       #get new lo
+       extv    $30,$32,r2,r0           #get new carry
+       beql    out                     # hi = 0, no work necessary
+       movl    r0,*16(sp)              # save hi
+       mcoml   r0,r0                   # Is hi = -1 (it'll fit in one word)
+       bneq    out                     # it doesn't
+       bisl2   $0xc0000000,*20(sp)     # alter low so that it is ok.
+out:   rsb
+
+
+
+/*
+ * pushframe : stack a frame 
+ * When this is called, the optional arguments and class have already been
+ * pushed on the stack as well as the return address (by virtue of the jsb)
+ * , we push on the rest of the stuff (see h/frame.h)
+ * for a picture of the save frame
+ */
+       .globl  _qpushframe
+
+_qpushframe:
+       Profile
+       movl    _errp,-(sp)
+       movl    _bnp,-(sp)
+       movl    NP,-(sp)
+       movl    LBOT,-(sp)
+       pushr   $0x3f00         # save r13(fp), r12(ap),r11,r10,r9,r8
+       movab   6*4(sp),r0      # return addr of lbot on stack
+       clrl    _retval         # set retval to C_INITIAL
+#ifndef SPISFP
+       jmp     *40(sp)         # return through return address
+#else
+       movab   -4(sp),sp
+       movl    sp,(sp)
+       movl    _xsp,-(sp)
+       jmp     *48(sp)
+#endif
+
+/*
+ * Ipushf : stack a frame, where space is preallocated on the stack. 
+ * this is like pushframe, except that it doesn't alter the stack pointer
+ * and will save more registers.
+ * This might be written a little more quickly by having a bigger register
+ * save mask, but this is only supposed to be an example for the
+ * IBM and RIDGE people.
+ */
+
+#ifdef SPISFP
+       .globl  _Ipushf
+_Ipushf:
+       .word   0
+       addl3   $96,16(ap),r1
+       movl    12(ap),-(r1)
+       movl    8(ap),-(r1)
+       movl    4(ap),-(r1)
+       movl    16(fp),-(r1)
+       movl    _errp,-(r1)
+       movl    _bnp,-(r1)
+       movl    NP,-(r1)
+       movl    LBOT,-(r1)
+       movl    r1,r0
+       movq    8(fp),-(r1) /* save stuff in the same order unix saves them
+                        (r13,r12,r11,r10,r9,r8) and then add extra
+                        for vms (sp,r7,r6,r5,r4,r3,r2) */
+       movq    r10,-(r1)
+       movq    r8,-(r1)
+       movab   20(ap),-(r1) /* assumes Ipushf allways called by calls, with
+                               the stack alligned */
+       movl    _xsp,-(r1)
+       movq    r6,-(r1)
+       movq    r4,-(r1)
+       movq    r2,-(r1)
+       clrl    _retval
+       ret
+#endif
+/*
+ * qretfromfr
+ * called with frame to ret to in r11.  The popnames has already been done.
+ * we must restore all registers, and jump to the ret addr. the popping
+ * must be done without reducing the stack pointer since an interrupt
+ * could come in at any time and this frame must remain on the stack.
+ * thus we can't use popr.
+ */
+
+       .globl  _qretfromfr
+
+_qretfromfr:
+       Profile
+       movl    r11,r0          # return error frame location
+       subl3   $24,r11,sp      # set up sp at bottom of frame
+       movl    sp,r1           # prepare to pop off
+       movq    (r1)+,r8        # r8,r9
+       movq    (r1)+,r10       # r10,r11
+       movq    (r1)+,r12       # r12,r13
+       movl    (r1)+,LBOT      # LBOT (lbot)
+       movl    (r1)+,NP        # NP (np)
+       jmp     *40(sp)         # jump out of frame
+
+#ifdef SPISFP
+
+/*
+ * this is equivalent to qretfro for a native VMS system
+ *
+ */
+       .globl  _Iretfrm
+_Iretfrm:
+       .word   0
+       movl    4(ap),r0        # return error frame location
+       movl    r0,r1
+       movq    -(r1),ap
+       movq    -(r1),r10
+       movq    -(r1),r8
+       movl    -(r1),sp
+       movl    -(r1),_xsp
+       movq    -(r1),r6
+       movq    -(r1),r4
+       movq    -(r1),r2
+       movl    r0,r1
+       movl    (r1)+,LBOT
+       movl    (r1)+,NP
+       jmp     *16(r0)
+#endif
+/*
+ * This routine gets the name of the inital entry point
+ * It is here so it can be under ifdef control.
+ */
+       .globl  _gstart
+_gstart:
+       .word   0
+#if os_vms
+       moval   _$$$start,r0
+#else
+       moval   start,r0
+#endif
+       ret
+       .globl  _proflush
+_proflush:
+       .word   0
+       ret
+
+/*
+ * The definition of mcount must be present even when the C code
+ * isn't being profiled, since lisp code may reference it.
+ */
+
+#ifndef os_vms
+.globl mcount
+mcount:
+#endif
+
+.globl _mcount
+_mcount:
+
+#ifdef PROF
+       movl    (r0),r1
+       bneq    incr
+       movl    _countbase,r1
+       beql    return
+       addl2   $8,_countbase
+       movl    (sp),(r1)+
+       movl    r1,(r0)
+incr:
+       incl    (r1)
+return:
+#endif
+       rsb
+
+       
+/* This must be at the end of the file.  If we are profiling, allocate
+ * space for the profile buffer
+ */
+#ifdef PROF
+       .data
+       .comm   _countbase,4
+       .lcomm  prbuf,indx+4
+       .text
+#endif
diff --git a/usr/src/ucb/lisp/franz/vax/vax.c b/usr/src/ucb/lisp/franz/vax/vax.c
new file mode 100644 (file)
index 0000000..3e6c177
--- /dev/null
@@ -0,0 +1,343 @@
+
+#ifndef lint
+static char *rcsid =
+   "$Header: vax.c,v 1.4 83/09/12 14:06:22 sklower Exp $";
+#endif
+
+/*                                     -[Mon Mar 21 19:35:50 1983 by jkf]-
+ *     vax.c                           $Locker:  $
+ * vax specific functions
+ *
+ * (c) copyright 1982, Regents of the University of California
+ */
+#include "global.h"
+#include <signal.h>
+#include "vaxframe.h"
+
+/* exarith(a,b,c,lo,hi)
+ * int a,b,c;
+ * int *lo, *hi;
+ * Exact arithmetic.
+ * a,b and c are 32 bit 2's complement integers
+ * calculates x=a*b+c to twice the precision of an int.
+ * In the vax version, the 30 low bits only are returned
+ * in *lo,and the next 32 bits of precision are returned in * hi.
+ * this works since exarith is used either for calculating the sum of
+ * two 32 bit numbers, (which is at most 33 bits), or
+ * multiplying a 30 bit number by a 32 bit numbers,
+ * which has a maximum precision of 62 bits.
+ * If *phi is 0 or -1 then
+ * x doesn't need any more than 31 bits plus sign to describe, so we
+ * place the sign in the high two bits of *lo and return 0 from this
+ * routine.  A non zero return indicates that x requires more than 31 bits
+ * to describe.
+ */
+exarith(a,b,c,phi,plo)
+int *phi, *plo;
+{
+asm("  emul    4(ap),8(ap),12(ap),r2   #r2 = a*b + c to 64 bits");
+asm("  extzv   $0,$30,r2,*20(ap)       #get new lo");
+asm("  extv    $30,$32,r2,r0           #get new carry");
+asm("  beql    out                     # hi = 0, no work necessary");
+asm("  movl    r0,*16(ap)              # save hi");
+asm("  mcoml   r0,r0                   # Is hi = -1 (it'll fit in one word)");
+asm("  bneq    out                     # it doesn't");
+asm("  bisl2   $0xc0000000,*20(ap)     # alter low so that it is ok.");
+asm("out:      ret");
+}
+
+mmuladd (a, b, c, m) 
+int a, b, c, m;
+{
+       asm ("emul      4(ap),8(ap),12(ap),r0");
+       asm ("ediv      16(ap),r0,r2,r0");
+}
+
+Imuldiv() {
+asm("  emul    4(ap),8(ap),12(ap),r0");
+asm("  ediv    16(ap),r0,*20(ap),*24(ap)");
+}
+
+callg_(funct,arglist)
+lispval (*funct)();
+int *arglist;
+{
+       asm("   callg   *8(ap),*4(ap)");
+}
+
+#include <errno.h>
+#define WRITE 4
+#define READ 3
+
+#ifdef os_vms
+#define _read _$real_read
+#define _write _$real_write
+#else
+#define _read(a,b,c) syscall(READ,a,b,c)
+#define _write(a,b,c) syscall(WRITE,a,b,c)
+#endif
+
+/*C library -- write
+  nwritten = write(file, buffer, count);
+  nwritten == -1 means error
+*/
+write(file, buffer, count)
+char *buffer;
+{
+       register lispval handy;
+       int retval;
+       if((file != 1) || (Vcntlw->a.clb == nil)) goto top;
+       /* since ^w is non nil, we do not want to print to the terminal,
+          but we must be sure to return a correct value from the write
+          in case there is no write to ptport
+       */
+       retval = count;
+       goto skipit;
+top:
+       retval = _write(file,buffer,count);
+
+skipit:
+    if(file==1) {
+       handy = Vptport->a.clb;
+       if(handy!=nil && TYPE(handy)==PORT && handy->p->_file!=1) {
+               fflush(handy->p);
+               file = handy->p->_file;
+               goto top;
+       }
+    }
+    return(retval);
+}
+
+/*
+ *
+ *nread = read(file, buffer, count);
+ *nread ==0 means eof; nread == -1 means error
+ *
+ */
+
+read(file,buffer,count)
+{
+       extern int errno;
+       register int Size;
+again:
+       Size = _read(file,buffer,count);
+       if ((Size >= 0) || (errno != EINTR)) return(Size);
+       if(sigintcnt > 0) sigcall(SIGINT);
+       goto again;
+}
+
+lispval
+Lpolyev()
+{
+       register int count; 
+       register double *handy, *base;
+       register struct argent *argp;
+       lispval result; int type;
+       char *alloca();
+       Keepxs();
+
+       count = 2 * (((int) np) - (int) lbot);
+       if(count == 0) 
+               return(inewint(0));
+       if(count == 8)
+               return(lbot->val);
+       base = handy = (double *) alloca(count);
+       for(argp = lbot; argp < np; argp++) {
+               while((type = TYPE(argp->val))!=DOUB && type!=INT)
+                       argp->val = (lispval) errorh2(Vermisc,"%%machine-polyev:non-real arg",nil,TRUE,73,lbot,argp->val);
+               if(TYPE(argp->val)==INT) {
+                       *handy++ = argp->val->i;
+               } else
+                       *handy++ = argp->val->r;
+       }
+       count = count/sizeof(double) - 2;
+       asm("polyd      (r9),r11,8(r9)");
+       asm("movd       r0,(r9)");
+       result = newdoub();
+       result->r = *base;
+       Freexs();
+       return(result);
+}
+
+lispval
+Lrot()
+{
+       register rot,val;               /* these must be the first registers */
+       register struct argent *mylbot = lbot;
+
+       chkarg(2,"rot");
+       if((TYPE(mylbot->val) != INT) || (TYPE(mylbot[1].val) != INT))
+               errorh2(Vermisc,
+                      "Non ints to rot",
+                      nil,FALSE,0,mylbot->val,mylbot[1].val);
+       val = mylbot[0].val->i;
+       rot = mylbot[1].val->i;
+       rot = rot % 32 ;        /* bring it down below one byte in size */
+       asm(" rotl r11,r10,r10 ");  /* rotate val by rot and put back in val */
+       return( inewint(val));
+}
+/* new version of showstack,
+       We will set fp to point where the register fp points.
+       Then fp+2 = saved ap
+            fp+4 = saved pc
+            fp+3 = saved fp
+            ap+1 = first arg
+       If we find that the saved pc is somewhere in the routine eval,
+   then we print the first argument to that eval frame. This is done
+   by looking one beyond the saved ap.
+*/
+lispval
+Lshostk()
+{      lispval isho();
+       return(isho(1));
+}
+static lispval
+isho(f)
+int f;
+{
+       register struct frame *myfp; register lispval handy;
+       int **fp;       /* this must be the first local */
+       int virgin=1;
+       lispval linterp();
+       lispval _qfuncl(),tynames();    /* locations in qfuncl */
+       extern int plevel,plength;
+
+       if(TYPE(Vprinlevel->a.clb) == INT)
+       { 
+          plevel = Vprinlevel->a.clb->i;
+       }
+       else plevel = -1;
+       if(TYPE(Vprinlength->a.clb) == INT)
+       {
+           plength = Vprinlength->a.clb->i;
+       }
+       else plength = -1;
+
+       if(f==1)
+               printf("Forms in evaluation:\n");
+       else
+               printf("Backtrace:\n\n");
+
+       myfp = (struct frame *) (&fp +1);       /* point to current frame */
+
+       while(TRUE)
+       {
+           if( (myfp->pc > eval  &&            /* interpreted code */
+                myfp->pc < popnames)
+               ||
+               (myfp->pc > Lfuncal &&          /* compiled code */
+                myfp->pc < linterp)  )
+           {
+             if(((int) myfp->ap[0]) == 1)              /* only if arg given */
+             { handy = (myfp->ap[1]);
+               if(f==1)
+                       printr(handy,stdout), putchar('\n');
+               else {
+                       if(virgin)
+                               virgin = 0;
+                       else
+                               printf(" -- ");
+                       printr((TYPE(handy)==DTPR)?handy->d.car:handy,stdout);
+               }
+             }
+
+           }
+
+           if(myfp > myfp->fp) break;  /* end of frames */
+           else myfp = myfp->fp;
+       }
+       putchar('\n');
+       return(nil);
+}
+
+/*
+ *
+ *     (baktrace)
+ *
+ * baktrace will print the names of all functions being evaluated
+ * from the current one (baktrace) down to the first one.
+ * currently it only prints the function name.  Planned is a
+ * list of local variables in all stack frames.
+ * written by jkf.
+ *
+ */
+lispval
+Lbaktrace()
+{
+       isho(0);
+}
+
+/*
+ * (int:showstack 'stack_pointer)
+ * return
+ *   nil if at the end of the stack or illegal
+ *   ( expresssion . next_stack_pointer) otherwise
+ *   where expression is something passed to eval
+ * very vax specific
+ */
+lispval
+LIshowstack()
+{
+    int **fp;  /* must be the first local variable */
+    register lispval handy;
+    register struct frame *myfp;
+    lispval retval, Lfuncal(), Ifuncal();
+    Savestack(2);
+    
+    chkarg(1,"int:showstack");
+
+    if((TYPE(handy=lbot[0].val) != INT) && (handy != nil))
+        error("int:showstack non fixnum arg", FALSE);
+
+    if(handy == nil)
+        myfp = (struct frame *) (&fp +1);
+    else
+        myfp = (struct frame *) handy->i;
+       
+    if((int ***)myfp <= &fp) error("int:showstack illegal stack value",FALSE);
+    while(myfp > 0)
+    {
+        if( (myfp->pc > eval  &&               /* interpreted code */
+            myfp->pc < popnames)
+           ||
+           (myfp->pc > Ifuncal &&              /* compiled code */
+           myfp->pc < Lfuncal)  )
+        {
+           if(((int) myfp->ap[0]) == 1)        /* only if arg given */
+           {
+               handy = (lispval)(myfp->ap[1]); /* arg to eval */
+
+               protect(retval=newdot());
+               retval->d.car = handy;
+               if(myfp > myfp->fp)
+                   myfp = 0;   /* end of frames */
+               else
+                   myfp = myfp->fp;
+               retval->d.cdr = inewint(myfp);
+               return(retval);
+           }
+       }
+       if(myfp > myfp->fp)
+            myfp = 0;  /* end of frames */
+       else
+            myfp = myfp->fp;
+
+    }
+    return(nil);
+}
+#ifdef SPISFP
+char *
+alloca(howmuch)
+register int howmuch;
+{
+       howmuch += 3 ;
+       howmuch >>= 2;
+       xsp -= howmuch
+       if (xsp < xstack) {
+               xsp += howmuch;
+               xserr();
+       }
+       return((char *) xsp);
+}
+#endif
diff --git a/usr/src/ucb/lisp/lispconf b/usr/src/ucb/lisp/lispconf
new file mode 100755 (executable)
index 0000000..7bf3aa0
--- /dev/null
@@ -0,0 +1,112 @@
+#!/bin/csh 
+#$Header: lispconf,v 1.14 83/09/12 15:20:50 sklower Exp $
+#
+# csh script to configure lisp
+# use:
+#      lispconf type
+# where type is one of
+#    vax_4_1 vax_4_1a vax_4_1c vax_eunice_vms
+#    sun_4_1c sun_unisoft dual_unisoft pixel_unisoft
+#
+if ($#argv == 1) then
+  set argument = $argv[1]
+else  
+  set argument = junk
+endif
+
+#fix makefile
+sed "s%^RootDir = .*%RootDir = `pwd`%" Makefile > Make$$
+mv Make$$ Makefile < /dev/null
+
+switch ($argument)
+ case vax_eunice_vms:
+       mv franz/vax/{Makefile,Make.unix}
+       mv franz/vax/{Make.vms,Makefile}
+ case vax_4_1:
+ case vax_4_1a:
+ case vax_4_1c:
+ case vax_4_2:
+ case sun_4_1c: 
+ case sun_unisoft:
+ case dual_unisoft:
+ case pixel_unisoft:
+       echo "/* this file created by ../../lispconf */" > franz/h/lconf.h
+       echo "#define $argv[1] 1" >> franz/h/lconf.h
+       rm -f franz/h/{aout,lispo}.h
+       cp /usr/include/a.out.h franz/h/aout.h
+       cp /usr/include/a.out.h franz/h/lispo.h
+       breaksw
+ default:
+  echo "use: lispconf type"
+  echo "  where type is one of "
+  echo "  vax_4_1 vax_4_1a vax_4_1c vax_4_2"
+  echo "  vax_eunice_vms"
+  echo "  sun_4_1c sun_unisoft dual_unisoft pixel_unisoft"
+  exit 1
+endsw 
+
+set ifusft=""
+switch ($argument)
+ case vax_*:
+       set VAX mach="vax"
+       (echo vax ucbstd; cat Makefile) | awk -f cvt.awk > Make$$
+       mv Make$$ Makefile < /dev/null
+       breaksw
+ case *_unisoft:
+       set ifusft="unisoft"
+ case sun_4_*: 
+       set M68K mach="68k"
+       (echo 68k $ifusft; cat Makefile) | awk -f cvt.awk > Make$$
+       mv Make$$ Makefile < /dev/null
+       breaksw
+endsw 
+
+# for the 68k version of the lisp compiler
+# The type of makefile built depends of the type of 68k
+#  system you have.  We assume that sun's have virtual memory
+#  and that dual/unisoft's have no vm (thus, define swapper).
+# As long as we are checking to see if we are dealing with
+# a 68000 unisoft machine; make some patches to the C part as well.
+if ($?M68K) then
+       switch ($argument)
+        case *_unisoft:
+               (echo swapper unisoft;\
+                   cat liszt/68k/Makefile) |awk -f cvt.awk > Make$$
+               (echo unisoft;\
+                   cat franz/68k/Makefile) |awk -f cvt.awk > franz/68k/Make$$
+               rm -f franz/h/{lispo,aout}.h
+               cp franz/h/duallispo.h franz/h/lispo.h
+               cp franz/h/dualaout.h franz/h/aout.h
+               cp franz/h/hpagsiz.h franz/h/pagsiz.h
+               cp lisplib/autorun/unisoft lisplib/autorun/68k
+               breaksw
+        case sun_4_1c:
+               (echo sun; cat liszt/68k/Makefile) | awk -f cvt.awk > Make$$
+               (echo sun; cat franz/68k/Makefile)\
+                               | awk -f cvt.awk > franz/68k/Make$$
+               cp lisplib/autorun/sun4.2 lisplib/autorun/68k
+               breaksw
+       endsw
+       rm -f liszt/68k/Makefile
+       sed "s%^RootDir = .*%RootDir = `pwd`%" Make$$ > liszt/68k/Makefile
+       rm -f Make$$
+       rm -f franz/68k/Makefile
+       mv franz/68k/Make$$ franz/68k/Makefile
+
+       if ($ifusft/x == unisoft/x) then
+               switch ($argument)
+                case sun_unisoft:
+                       set OFFSET=0x8000
+                       breaksw
+                case dual_unisoft:
+                       set OFFSET=0x800000
+                       breaksw
+                case pixel_unisoft:
+                       set OFFSET=0x20000
+                       breaksw
+               endsw
+               sed "s%^OFFSET = .*%OFFSET = $OFFSET%"\
+                               lisplib/autorun/68k > temp$$
+               mv temp$$ lisplib/autorun/68k </dev/null
+       endif
+endif
diff --git a/usr/src/ucb/lisp/lisplib/Makefile b/usr/src/ucb/lisp/lisplib/Makefile
new file mode 100644 (file)
index 0000000..c914f29
--- /dev/null
@@ -0,0 +1,139 @@
+# $Header: /usr/lib/lisp/RCS/Makefile,v 1.9 83/08/15 22:28:27 jkf Exp $
+#      Makefile for /usr/lib/lisp
+# this directory contains the lisp coded portion of the standard 
+# lisp system and other useful lisp programs. 
+# The command 'make all' insures that all source files are compiled
+# The command 'make install' installs these files in the standard
+# place (/usr/lib/lisp).  This is only useful of course if the current
+# directory is not /usr/lib/lisp.
+#
+.SUFFIXES: .l.s.o
+
+.l.s:
+       ${Liszt} -xaqS $*
+.l.o:
+       ${Liszt} -xaq $*
+
+#--- Default paths and programs:
+LibDir = /usr/lib/lisp
+CopyTo = /dev/null
+Liszt = liszt
+
+
+#--- ReqSrc: required source for building lisp system
+#
+ReqSrc = charmac.l common0.l common1.l common2.l common3.l toplevel.l \
+       syntax.l  macros.l  vector.l array.l pp.l format.l version.l \
+       tpl.l fcninfo.l
+
+
+#--- OtherSrc: other lisp coded library files
+OtherSrc = machacks.l loop.l ucifnc.l  ucido.l jkfmacs.l trace.l\
+       syscall.l \
+       cmumacs.l cmufncs.l fix.l step.l cmufile.l cmutpl.l cmuedit.l \
+       structini.l struct.l prof.l hash.l flavorm.l lmhacks.l
+
+LocalSrc = describe.l flavors.l vanilla.l
+
+ReqObj = charmac.o common0.o common1.o common2.o common3.o toplevel.o \
+       syntax.o  macros.o  vector.o array.o pp.o format.o version.o \
+       tpl.o fcninfo.o
+
+OtherObj = machacks.o loop.o ucifnc.o  ucido.o jkfmacs.o trace.o\
+       syscall.o\
+       cmumacs.o cmufncs.o fix.o step.o cmufile.o cmutpl.o cmuedit.o \
+       struct.o prof.o hash.o flavorm.o lmhacks.o
+
+LocalObj =  describe.o flavors.o vanilla.o
+
+#--- AllSrc: all source files required for lisp system
+#              LocalSrc isn't included!
+AllSrc = Makefile ReadMe buildlisp.l cmuenv.l fixit.ref \
+       ${ReqSrc} ${OtherSrc} autorun/vax autorun/unisoft autorun/sun4.2
+
+AllObj = ${ReqObj} ${OtherObj}
+    
+all: ${AllObj}
+
+local-all: ${AllObj} ${LocalObj}
+
+required: ${ReqObj}
+
+DotSSrc = charmac.s common0.s common1.s\
+         common2.s common3.s toplevel.s syntax.s macros.s\
+         vector.s array.s pp.s format.s\
+         version.s tpl.s fcninfo.s
+
+xtra:  ${DotSSrc}
+
+fromasm:
+       for i in *.s; do echo $$i; ${LibDir}/as $$i; done
+#      rm -f *.s
+
+
+## defstruct should be compiled with a compiled version of itself.
+## When a compiled form doesn't exist, structini.l can be used to
+## build a struct.o which is close but not exactly what you want.
+## Recompiling struct will use struct.o and create the correct struct.o
+## 
+struct-again:
+       ${Liszt} -xaq struct
+
+## this will only work if you have an up to date version of ctags which
+## understands lisp files.
+
+tags:    ${AllSrc}
+       ctags ${AllSrc}
+
+sources: ${AllSrc}
+
+xref:
+       lxref ${AllSrc} > xref
+
+echofiles:
+       @echo ${ReqSrc} ${OtherSrc}
+
+echorequired:
+       @echo ${ReqSrc}
+
+# updatemachine will vcp all objects and source to machine
+# named with 'mach' on the command line
+
+updatemachine: ${AllSrc} ${AllObj}
+       -vcp -wfq /usr/ucb/lisp /usr/ucb/liszt ${mach}:.
+       -vcp -wfq ${AllSrc} ${mach}:/usr/lib/lisp
+       -vcp -wfq ${AllObj} ${mach}:/usr/lib/lisp
+
+copysource: ${AllSrc}
+       (tar cf - ${AllSrc} | (cd ${CopyTo} ; tar xf -))
+
+copyobjects: ${AllObj}
+       (tar cf - ${AllObj} | (cd ${CopyTo} ; tar xf -))
+
+scriptcatall: ${AllSrc}
+       @(X=`pwd` ; cd ${CdTo}; scriptcat $$X lisplib ${AllSrc})
+
+scriptcatxtra:
+       @(X=`pwd` ; cd ${CdTo}; scriptcat $$X lisplib ${DotSSrc})
+
+as:
+       @echo "Grabbing as from /bin"
+       cp /bin/as as
+
+nld:
+       @echo "Grabbing nld from /bin"
+       cp /bin/ld nld
+
+cleanreq:
+       -rm -f ${ReqObj}
+
+cleanall:
+       -rm -f ${AllObj}
+
+cleanother:
+       -rm -f ${OtherObj}
+
+clean: 
+       -rm -f *.o 
+       -rm -f *.blat 
+       -rm -f *.x
diff --git a/usr/src/ucb/lisp/lisplib/buildlisp.l b/usr/src/ucb/lisp/lisplib/buildlisp.l
new file mode 100644 (file)
index 0000000..e1a3460
--- /dev/null
@@ -0,0 +1,101 @@
+(int:setsyntax '\; 'splicing 'zapline)
+;; buildlisp.l                         -[Mon Aug 15 11:04:31 1983 by jkf]-
+;; build the lisp system from the C kernel
+;; the order of these files is very important.
+;;
+(setq rcs-buildlisp-
+   "$Header: /usr/lib/lisp/RCS/buildlisp.l,v 1.2 83/08/15 22:16:06 jkf Exp $")
+
+; variables to modify the way buildlisp works:
+;   build:dir -- directory containing the object files to load
+;      default: /usr/lib/lisp
+;   build:map -- map file to write the fasl map into.
+;      default: no map is written
+;   build:load -- if t then only loading will be done, no fasl'ing
+;   build:lisp-type -- may contain a site dependent name to help build
+;              a personalized lisp
+;   lisp-library-directory -- directory which will contain lisp library
+;      this directory will be part of the default search path
+;   lisp-object-directory -- directory which contains the lisp object file
+;
+(or (boundp 'build:dir) (setq build:dir '/usr/lib/lisp))
+(or (boundp 'build:map) (setq build:map nil))
+(or (boundp 'build:load) (setq build:load nil))
+(or (boundp 'build:lisp-type) (setq build:lisp-type 'franz))
+(or (boundp 'lisp-library-directory)
+   (setq lisp-library-directory '/usr/lib/lisp))
+(or (boundp 'lisp-object-directory)
+   (setq lisp-object-directory '/usr/ucb))
+
+
+(def build:load
+   (lambda (x)
+      (prog (name)
+        (setq name (concat build:dir "/" x))
+        (cond (build:map
+                 (fasl-or-load name t build:map)
+                       ; concatentate to map after first file loaded
+                       (cond ((null (status appendmap))
+                              (sstatus appendmap t))))
+                    (t (fasl-or-load name nil nil))))))
+
+(def fasl-or-load
+   (lambda (name provide-map map-name)
+      (prog  (tempname)
+      (cond ((and (null build:load)
+                 (probef (setq tempname (concat name ".o"))))
+            (cond (provide-map (fasl tempname map-name))
+                  (t (fasl name))))
+           ((probef (setq tempname (concat name ".l")))
+            (load tempname))
+           (t (patom "fasl-or-load: Can't find file: ")
+              (patom name)
+              (terpr)
+              (exit 1)  ; just go away fast so user will realize problem
+           )))))
+              
+             
+(build:load 'common0)
+(build:load 'syntax)
+(build:load 'charmac)
+(build:load 'macros)
+(build:load 'common1)
+(build:load 'common2)
+(build:load 'common3)
+(build:load 'vector)
+(build:load 'array)
+(build:load 'pp)
+
+; only load format if it is compiled. This will save some time when
+; building an interpreted lisp system
+(cond ((probef (concat build:dir "/format.o"))
+       (build:load 'format)))
+
+(build:load 'version)
+
+(and (not (eq build:lisp-type 'zlisp))
+     (build:load 'tpl))
+
+(build:load 'toplevel)
+
+(cond ((eq build:lisp-type 'franz))
+      ((eq build:lisp-type 'zlisp)
+       (build:load 'zlisp))
+      (t (patom "Invalid lisp type: ")
+        (patom build:lisp-type)
+        (terpr)
+        (exit 1)))
+
+; kill definitions
+(putd 'fasl-or-load  nil)
+(putd 'build:load nil)
+(allocate 'hunk3 2)    ; make space for format to use
+(new-vector 1024)
+(new-vectori-long 512)
+(gc)
+
+
+
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/common0.l b/usr/src/ucb/lisp/lisplib/common0.l
new file mode 100644 (file)
index 0000000..b73b89c
--- /dev/null
@@ -0,0 +1,274 @@
+(setq rcs-common0-
+   "$Header: common0.l,v 1.3 83/09/07 08:12:49 jkf Exp $")
+
+;;
+;;  common0.l                          -[Sun Sep  4 13:44:22 1983 by jkf]-
+;;
+;;   Functions which are required to execute the low level lisp macros
+;; and functions.
+;;
+;;   This is the first file of functions read in when building a lisp.
+;; If this lisp is to run interpretedly, then we must not use anything
+;; which hasn't be defined in the C lisp kernel, except ';' which is
+;; defined as the comment character before reading this file.
+;; We cannot use defmacro, the backquote or the # macro.
+;;
+;;   This file should be as short as possible since it must be written in
+;; a rather primitive way.
+;;
+
+;--- declare : ignore whatever is given, this info is for the compiler
+;
+(def declare (nlambda (x) nil))
+
+(declare (macros t))
+
+;--- memq - arg : (probably a symbol)
+;        - lis : list
+; returns part of lis beginning with arg if arg is in lis
+;      
+(def memq
+  (lambda ($a$ $l$)
+         (do ((ll $l$ (cdr ll)))
+             ((null ll) nil)
+             (cond ((eq $a$ (car ll)) (return ll))))))
+
+;--- def :: define a function
+; This superceeds franz's definition.
+; It does more error checking and it does lambda conversion
+;
+(def def
+   (nlambda (l)
+     ((lambda (name argl)
+       (cond ((and (symbolp (setq name (car l)))
+                   (dtpr (cadr l))
+                   (null (cddr l))
+                   (memq (caadr l) '(lambda nlambda lexpr macro)))
+              ; make sure lambda list is nil or a dtpr
+              (setq l (cadr l))  ; l points to (lambda (argl) ...)
+              (cond ((null (setq argl (cadr l))))      ; nil check
+                    ((dtpr (cadr l))                   ; dtpr
+                     (cond ((and (eq (car l) 'lambda)
+                                 (or (memq '&aux argl)
+                                     (memq '&optional argl)
+                                     (memq '&rest argl)
+                                     (memq '&body argl)))
+                            ; must lambda convert
+                            (setq l (lambdacvt (cdr l))))))
+                    (t (error "def: bad lambda list of form in " l)))
+              (putd name l)
+              name)
+             (t (error "def: bad form " l))))
+      nil nil)))
+                            
+
+;--- defun
+; maclisp style function defintion
+;
+(def defun
+   (macro (l)
+      (prog (name type arglist body specind specnam)
+        (setq name (cadr l) l (cddr l))
+        (cond ((dtpr name)
+               (cond ((memq (cadr name) '(macro expr fexpr lexpr))
+                      (setq l (cons (cadr name) l)
+                            name (car name)))
+                     (t (setq specnam (car name)
+                              specind (cadr name)
+                              name (concat (gensym) "::" specnam))))))
+        (cond ((null (car l)) (setq type 'lambda))
+              ((eq 'fexpr (car l)) (setq type 'nlambda l (cdr l)))
+              ((eq 'expr (car l))  (setq type 'lambda l (cdr l)))
+              ((eq 'macro (car l)) (setq type 'macro l (cdr l)))
+              ((atom (car l))
+               (setq type 'lexpr
+                     l (nconc (list (list (car l)))
+                              (cdr l))))
+              (t (setq type 'lambda)))
+        (setq body (list 'def name (cons type l)))
+        (cond (specnam
+                 (return (list 'progn ''compile
+                               body
+                               (list 'putprop
+                                     (list 'quote specnam)
+                                     (list 'getd
+                                           (list 'quote name))
+                                     (list 'quote specind)))))
+              (t (return body))))))
+
+
+;--- error : print error message and cause an error
+;  call is usually (error "string" value)
+;
+(def error
+   ;; form: (error arg1 ...)
+   ;; concat all args together, with spaces between them
+   ;; and cause an error to be signaled
+  (lexpr (n)
+        (do ((i n (1- i))
+             (mesg ""))
+            ((eq i 0) (err-with-message mesg))
+            (setq mesg (concat
+                          (cond ((atom (arg i)) (arg i))
+                                (t (implode (exploden (arg i)))))
+                          " " mesg)))))
+
+(def err
+   ;; (err value [junk])
+   ;; This is here for maclisp compatibility.  junk should be nil,
+   ;; but we don't verify.
+   ;; The value is both to be printed and to be returned from the
+   ;; errset.  'err-with-message' should be used for new code
+   (lexpr (n)
+         (cond ((eq n 0)
+                (err-with-message "call to err"))
+               ((or (eq n 1) (eq n 2))
+                (err-with-message (arg 1) (arg 1)))
+               (t (error "wrong number of args to err:" n)))))
+
+
+;--- append : append two or more lists
+; the result will be a copy of all but the last list
+;
+(declare (localf append2args))         
+
+(def append
+  (lexpr (nargs)
+        (cond ((eq nargs 2) (append2args (arg 1) (arg 2)))
+              ((zerop nargs) nil)
+              (t (do ((i (1- nargs) (1- i))
+                      (res (arg nargs)))
+                     ((zerop i) res)
+                     (setq res (append2args (arg i) res)))))))
+
+;--- append2args : append just two args
+; a version of append which only works on 2 arguments
+;
+(def append2args 
+  (lambda (x y)
+         (prog (l l*)
+               (cond ((null x) (return y))
+                     ((atom x) (error "Non-list to append:" x)))
+               (setq l* (setq l (cons (car x) nil)))
+       loop    (cond ((atom x) (error "Non-list to append:" x))
+                     ((setq x (cdr x))
+                      (setq l* (cdr (rplacd l* (cons (car x) nil))))
+                      (go loop)))
+               (rplacd l* y)
+               (return l))))
+
+;--- append1 : add object to end of list
+; adds element y to then end of a copy of list x
+;
+(def append1 (lambda (x y) (append x (list y))))
+
+;--- assoc - x : lispval
+;         - l : list
+;      l is a list of lists. The list is examined and the first
+;      sublist whose car equals x is returned.
+;
+(def assoc
+  (lambda (val alist)
+         (do ((al alist (cdr al)))
+             ((null al) nil)
+             (cond ((null (car al)))
+                   ((not (dtpr (car al)))
+                    (error "bad arg to assoc" al))
+                   ((equal val (caar al)) (return (car al)))))))
+
+;--- rassq : like assq but look at the cdr instead of the car
+;
+(def rassq
+   (lambda (form list)
+      (cond ((null list) nil)
+           ((not (dtpr list))
+            (error "rassq: illegal second argument: " list))
+           (t (do ((ll list (cdr ll)))
+                  ((null ll) nil)
+                  (cond ((eq form (cdar ll)) (return (car ll)))))))))
+;--- concatl - l : list of atoms
+;      returns the list of atoms concatentated
+;
+(def concatl
+ (lambda (x) (apply 'concat x)))
+
+;--- length - l : list
+;      returns the number of elements in the list.
+;
+(def length
+   (lambda ($l$)
+      (cond ((and $l$ (not (dtpr $l$)))
+            (error "length: non list argument: " $l$))
+           (t (cond ((null $l$) 0)
+                    (t (do ((ll (cdr $l$)  (cdr ll))
+                            (i 1 (1+ i)))
+                           ((null ll) i))))))))
+
+;--- memq - arg : (probably a symbol)
+;        - lis : list
+; returns part of lis beginning with arg if arg is in lis
+;      
+(def memq
+  (lambda ($a$ $l$)
+         (do ((ll $l$ (cdr ll)))
+             ((null ll) nil)
+             (cond ((eq $a$ (car ll)) (return ll))))))
+
+;--- nconc - x1 x2 ...: lists
+;      The cdr of the last cons cell of xi is set to xi+1.  This is the
+;      structure modification version of append
+;
+
+(def nconc 
+  (lexpr (nargs) 
+        (cond ((eq nargs '2) 
+               (cond ((null (arg 1)) (arg 2))
+                     (t (do ((tmp (arg 1) (cdr tmp)))
+                            ((null (cdr tmp)) 
+                             (rplacd tmp (arg 2))
+                             (arg 1))))))
+              ((zerop nargs) nil)
+              (t (do ((i 1 nxt)
+                      (nxt 2 (1+ nxt))
+                      (res (cons nil (arg 1)))) 
+                     ((eq i nargs) (cdr res))
+                     (cond ((arg i) (rplacd (last (arg i)) (arg nxt)))
+                           (t (rplacd (last res) (arg nxt)))))))))
+
+
+
+(declare (localf nreverse1))   ; quick fcn shared by nreverse and nreconc
+
+;--- nreconc :: nreverse and nconc
+; (nreconc list elemt) is equiv to (nconc (nreverse list) element)
+;
+(defun nreconc (list element)
+  (cond ((null list) element)
+       (t (nreverse1 list element))))
+
+;--- nreverse - l : list
+;      reverse the list in place
+;
+
+(defun nreverse (x)
+  (cond ((null x) x)
+       (t (nreverse1 x nil))))
+
+
+;--- nreverse1
+;  common local function to nreconc and nreverse.  [This can just be
+; nreconc when I get local global functions allow in the compiler -jkf]
+;
+(defun nreverse1 (x ele)
+  (prog (nxt)
+  loop
+       (setq nxt (cdr x))
+       (rplacd x ele)
+       (setq ele x)
+       (cond (nxt (setq x nxt) (go loop)))
+       (return x)))
+
+;--- liszt-declare :: this is defined in the compiler
+; we give it a null definition in the interpreter
+;
+(def liszt-declare (nlambda (x) nil))
diff --git a/usr/src/ucb/lisp/lisplib/common1.l b/usr/src/ucb/lisp/lisplib/common1.l
new file mode 100644 (file)
index 0000000..1cb4e0e
--- /dev/null
@@ -0,0 +1,1432 @@
+(setq rcs-common1-
+   "$Header: common1.l,v 1.8 83/09/07 08:17:20 jkf Exp $")
+
+;;
+;; common1.l                           -[Sun Sep  4 14:04:15 1983 by jkf]-
+;;
+;;   common lisp functions.  These are the most common lisp functions
+;; [which don't have to be defined in common0.l in order to support 
+;;  the macros]
+;;
+
+(declare (macros t))           ;; compile macros in this file
+
+;--- Section 0 - variables
+(declare (special Standard-Input Standard-Output Standard-Error
+                 lisp-library-directory))
+
+(or (boundp 'lisp-library-directory)
+   (setq lisp-library-directory '/usr/lib/lisp))
+
+
+;--- Section 0 - equivalences
+; 
+(defmacro make-equivalent (a b)
+   `(progn (putd ',a (getd ',b))
+          (putprop ',a (get ',b 'fcn-info) 'fcn-info)))
+
+(make-equivalent abs absval)
+(make-equivalent add sum)
+(make-equivalent bcdcall funcall)
+(make-equivalent chrct charcnt)
+(make-equivalent diff difference)
+(make-equivalent numbp  numberp)
+(make-equivalent remainder mod)
+(make-equivalent terpri terpr)
+(make-equivalent typep type)
+(make-equivalent symeval eval)
+(make-equivalent < lessp)
+(make-equivalent <& lessp)     ; fixnum version
+(make-equivalent = equal)
+(make-equivalent =& equal)     ; fixnum version
+(make-equivalent > greaterp)
+(make-equivalent >& greaterp)  ; fixnum version
+(make-equivalent *dif difference)
+(make-equivalent \\ mod) 
+(make-equivalent \1+$ add1)
+(make-equivalent \1-$ sub1)
+(make-equivalent *$ times)
+(make-equivalent /$ quotient)
+(make-equivalent +$ add)
+(make-equivalent -$ difference)
+
+;--- Section I - functions and macros
+
+
+;--- max - arg1 arg2 ... : sequence of numbe
+;      returns the maximum
+;
+(def max
+  (lexpr (nargs)
+        (do ((i nargs (1- i))
+             (max (arg 1)))
+            ((< i 2) max)
+            (cond ((greaterp (arg i) max) (setq max (arg i)))))))
+
+
+;--- catch form [tag]  
+;  catch is now a macro which translates to (*catch 'tag form)
+;
+(def catch
+  (macro (l)
+        `(*catch ',(caddr l) ,(cadr l))))
+
+;--- throw form [tag]
+;  throw isnow a macro
+;
+(def throw
+  (macro (l)
+        `(*throw ',(caddr l) ,(cadr l))))
+
+
+      
+;--- desetq
+;      - pattern - pattern containing vrbl names
+;      - expr    - expression to be evaluated
+;
+(defmacro desetq (&rest forms &aux newgen destrs)
+  (do ((xx forms (cddr xx))
+       (res)
+       (patt)
+       (expr))
+      ((null xx) (cond ((null (cdr res)) (car res))
+                      (t (cons 'progn (nreverse res)))))
+      (setq patt (car xx) expr (cadr xx))
+      (setq res 
+           (cons (cond ((atom patt) `(setq ,patt ,expr))       ;trivial case
+                       (t (setq newgen (gensym)
+                                destrs (de-compose patt '(r)))
+                          `((lambda (,newgen)
+                                    ,@(mapcar '(lambda (frm)
+                                                       `(setq  ,(cdr frm) 
+                                                               (,(car frm) ,newgen)))
+                                              destrs)
+                                    ,newgen)
+                            ,expr)))
+                 res))))
+
+;--- sassoc
+;      - x : form
+;      - y : assoc list
+;      - fcn : function or lambda expression
+; If (assoc x y) is non nil, then we apply the function fcn to nil.  
+; This must be written as a macro if we expect to handle the case of
+; a lambda expression as fcn in the compiler.  
+;
+(defmacro sassoc (x y fcn)
+  (cond ((or (atom fcn) (not (eq 'quote (car fcn))))
+        `(or (assoc ,x ,y)
+             (funcall ,fcn)))
+       (t `(or (assoc ,x ,y)
+               (,(cadr fcn))))))
+
+;--- sassq
+;      - x : form
+;      - y : assoc list
+;      - fcn : function or lambda expression
+; like sassoc above except it uses assq instead of assoc.
+;
+(defmacro sassq (x y fcn)
+  (cond ((or (atom fcn) (not (eq 'quote (car fcn))))
+        `(or (assq ,x ,y)
+             (funcall ,fcn)))
+       (t `(or (assq ,x ,y)
+               (,(cadr fcn))))))
+
+                   
+
+;--- signp - test - unevaluated atom
+;         - value - evaluated value
+; test can be l, le, e, n, ge or g   with the obvious meaning
+; we return t if value compares to 0 by test
+
+(defmacro signp (tst val)
+  (setq tst  (cond ((eq 'l tst)  `(minusp signp-arg))
+                  ((eq 'le tst) `(not (greaterp signp-arg 0)))
+                  ((eq 'e tst)  `(zerop signp-arg))
+                  ((eq 'n tst)  `(not (zerop signp-arg)))
+                  ((eq 'ge tst) `(not (minusp signp-arg)))
+                  ((eq 'g tst)  `(greaterp signp-arg 0))
+                  (t (error "bad arg to signp " tst))))
+  (cond ((atom val) `(and (numberp ,val) ,(subst val 'signp-arg tst)))
+       (t `((lambda (signp-arg) (and (numberp signp-arg) ,tst))
+            ,val))))
+
+
+
+;--- unwind-protect
+;  The form of a call to unwind-protect is
+;   (unwind-protect pform
+;                  form1 form2 ...)
+; and it works as follows:
+;  pform is evaluated, if nothing unusual happens, form1 form2 etc are
+;      then evaluated and unwind-protect returns the value of pform.
+;  if while evaluating pform, a throw or error caught by an errset which
+;   would cause control to pass through the unwind-protect, then
+;   form1 form2 etc are evaluated and then the error or throw continues.
+; Thus, no matter what happens, form1, form2 etc will be evaluated.
+;
+(defmacro unwind-protect (protected &rest conseq &aux (localv (gensym 'G)))
+  `((lambda (,localv)
+           (setq ,localv (*catch 'ER%unwind-protect ,protected))
+           ,@conseq
+           (cond ((and (dtpr ,localv) (eq 'ER%unwind-protect (car ,localv)))
+                  (I-throw-err (cdr ,localv)))
+                 (t ,localv)))
+    nil))
+
+
+;----Section III -- Interrupt handlers 
+; 
+
+(def sys:fpeint-serv
+   (lambda (x$) (error "Floating Exception ")))
+
+(def sys:int-serv
+   (lambda (dummy) (patom '"Interrupt:\a  ") (drain) (break)))
+
+
+(signal 8 'sys:fpeint-serv)
+(signal 2 'sys:int-serv)
+
+\f
+;---- Section IV - interrupt handlers
+;
+(cond ((null (boundp '$gcprint))
+       (setq $gcprint nil)))           ; dont print gc stats by default
+
+(cond ((null (boundp '$gccount$))
+       (setq $gccount$ 0)))
+
+;--- prtpagesused - [arg] : type of page allocated last time.
+;      prints a summary of pages used for certain selected types
+;      of pages.  If arg is given we put a star beside that type
+;      of page.  This is normally called after a gc.
+;
+(def prtpagesused
+  (lambda (space tottime gctime)
+         (patom "[")
+         (do ((curtypl (cond ((memq space '(list fixnum ))
+                              '(list fixnum))
+                             (t (cons space '(list fixnum))))
+                       (cdr curtypl))
+              (temp))
+             ((null curtypl) (print 'ut:)
+              (print (max 0 (quotient (times 100 (difference tottime gctime))
+                                      tottime)))
+              (patom "%]") (terpr))
+             (setq temp (car curtypl))
+             (cond ((greaterp (cadr (opval temp)) 0)
+                    (cond ((eq space temp)
+                           (patom '*)))
+                    (patom temp)
+                    (patom '":")
+                    (print (cadr (opval temp)))
+                    (patom '"{")
+                    (print (fix (quotient 
+                                 (times 100.0
+                                        (car (opval temp)))
+                                 (* (cadr (opval temp))
+                                        (caddr (opval temp))))))
+                    (patom '"%}")
+                    (patom '"; "))))))
+
+(declare (special gcafter-panic-mode $gccount$ $gc_midlim $gc_minalloc 
+                 $gc_pct $gc_lowlim $gcprint ptimeatlastgc))
+
+(setq gcafter-panic-mode nil)
+(setq $gc_minalloc 10)
+(setq $gc_lowlim 60)
+(setq $gc_midlim 85)
+(setq $gc_pct    .10)
+(setq ptimeatlastgc (ptime))
+
+;--- gcafter - [s] : type of item which ran out forcing garbage collection.
+;      This is called after each gc.
+; the form of an opval element is  (number_of_items_in_use
+;                                  number_of_pages_allocated
+;                                  number_of_items_per_page)
+;
+;
+(def gcafter 
+  (nlambda (s)
+          (prog (x pct amt-to-allocate thisptime diffptime difftottime
+                   diffgctime)
+                (cond ((null s) (return)))  
+                (cond ((null (boundp '$gccount$)) (setq $gccount$ 0)))
+                (setq $gccount$ (1+ $gccount$))
+                (setq x (opval (car s)))
+                (setq thisptime (ptime)
+                      difftottime (max  (difference (car thisptime)
+                                                    (car ptimeatlastgc))
+                                        1)
+                      diffgctime (difference (cadr thisptime)
+                                             (cadr ptimeatlastgc))
+                      ptimeatlastgc thisptime)
+                ; pct is the percentage of space used
+                (setq pct (quotient (times 100 (car x))
+                                    (max 1 (times (cadr x) (caddr x)))))
+                (setq amt-to-allocate
+                      (cond (gcafter-panic-mode 
+                             (cond ((greaterp pct 95) 
+                                    (patom "[Storage space totally exhausted]")
+                                    (terpr)
+                                    (error "Space exhausted when allocating "
+                                           (car s)))
+                                   (t 0)))
+                            ((greaterp pct $gc_midlim)
+                             (max $gc_minalloc (fix (times $gc_pct (cadr x)))))
+                            ((greaterp pct $gc_lowlim)
+                             $gc_minalloc)
+                            ((lessp (cadr x) 100)
+                             $gc_minalloc)
+                            (t 0)))
+                (cond ((and (null gcafter-panic-mode) (greaterp amt-to-allocate
+                                                                0))
+                       (cond ((atom (errset (allocate (car s) amt-to-allocate)))
+                              (cond ($gcprint 
+                                       (patom "[Now in storage allocation panic mode]")
+                                       (terpr)))
+                              (setq gcafter-panic-mode t)))))
+
+                (cond ($gcprint (prtpagesused (car s) difftottime diffgctime)
+                                (comment (cond ((and (getd 'gcstat)
+                                            (eq $gcprint '$all))
+                                       (print (gcstat))
+                                       (terpr)))))))))
+\f
+;----Section V - the functions
+; 
+
+
+;--- bigp - x : lispval
+;      returns t if x is a bignum
+;
+(def bigp (lambda (arg) (equal (type arg) 'bignum)))
+
+;--- comment - any
+;      ignores the rest of the things in the list
+(def comment
+  (nlambda (x) 'comment))
+
+
+;--- copy - l : list (will work if atom but will have no effect)
+;      makes a copy of the list.
+; will also copy vector and vectori's, if their property list
+; doesn't have the 'unique' flag
+;
+(def copy
+   (lambda (l)
+      (cond ((dtpr l) (cons (copy (car l)) (copy (cdr l))))
+           ((vectorp l)
+            (if (vget l 'unique)
+               then l
+               else (let ((size (vsize l)))
+                       (do ((newv (new-vector size))
+                            (i 0 (1+ i)))
+                           ((not (<& i size))
+                            (vsetprop newv (copy (vprop l)))
+                            newv)
+                           (vset newv i (copy (vref l i)))))))
+           ((vectorip l)
+            (if (vget l 'unique)
+               then l
+               else (let ((size (vsize-byte l)))
+                       (do ((newv (new-vectori-byte size))
+                            (i 0 (1+ i)))
+                           ((not (<& i size))
+                            (vsetprop newv (copy (vprop l)))
+                            newv)
+                           (vseti-byte newv i (vrefi-byte l i))))))
+           (t l))))
+
+
+;--- copysymbol - sym : symbol to copy
+;              - flag : t or nil
+;  generates an uninterned symbol with the same name as sym.  If flag is t
+; then the value, function binding and property list of sym are placed
+; in the uninterned symbol.
+;
+(def copysymbol 
+  (lambda (sym flag)
+         ((lambda (newsym)
+                  (cond (flag (cond ((boundp sym) (set newsym (eval sym))))
+                              (putd newsym (getd sym))
+                              (setplist newsym (plist sym))))
+
+                  newsym)
+          (uconcat sym))))
+
+
+;--- cvttointlisp -- convert reader syntax to conform to interlisp
+;
+(def cvttointlisp
+  (lambda nil
+         (setsyntax '\% 'vescape)              ; escape character
+         (setsyntax '\\ 'vcharacter)           ; normal character
+         (setsyntax '\` 'vcharacter)           ; normal character
+         (setsyntax '\, 'vcharacter)           ; normal character
+         (sstatus uctolc t)                    ; one case
+         ))
+
+
+;--- cvttomaclisp - converts the readtable to a maclisp character syntax
+;
+(def cvttomaclisp
+  (lambda nil
+         (setsyntax '\/ 'vescape)              ; escape
+         (setsyntax '\\ 'vcharacter)           ; normal char
+         (setsyntax '\[ 'vcharacter)           ; normal char
+         (setsyntax '\] 'vcharacter)           ; normal char
+         (sstatus uctolc t)))
+
+(declare (special readtable))
+;--- cvttoucilisp - converts the readtable to a ucilisp character syntax
+;
+(def cvttoucilisp
+  (lambda nil
+         (sstatus uctolc t)            ; upper case to lower case
+                                       ; change backquote character.
+                                       ; to ` and ! and !@ from ` , and ,@
+                                       ; undo comma.
+       (setsyntax '\! 'splicing (get '\, readtable))
+       (setsyntax '\, 'vcharacter)
+               ; 
+               ; ~ as comment character, not ; and / instead of \ for escape
+       (setsyntax '\~ 'splicing 'zapline)
+       (setsyntax '\; 'vcharacter)
+       (setsyntax '\/ 'vescape)
+       (setsyntax '\\   'vcharacter)))
+
+
+;--- cvttofranzlisp - converts the readtable to the standard franz readtable
+; this just does the obvious conversions, assuming that the user was
+; in the maclisp syntax before.
+(def cvttofranzlisp
+   (lambda nil
+      (setsyntax '\/ 'vcharacter)
+      (setsyntax '\\ 'vescape)
+      (setsyntax '\[ 'vleft-bracket)
+      (setsyntax '\] 'vright-bracket)
+      (sstatus uctolc nil)))
+
+;--- defprop - like putprop except args are not evaled
+;
+(def defprop 
+    (nlambda (argl)
+       (putprop (car argl) (cadr argl) (caddr argl) )))
+
+;--- delete
+;      - val - lispval
+;      - lst - list
+;      - n   - Optional arg, number of occurances to delete
+; removes up to n occurances of val from the top level of lst.
+; if n is not given, all occurances will be removed.
+;
+(def delete
+  (lexpr (nargs)
+        (prog (val lst cur ret nmb)
+              (cond ((= nargs 2)
+                     (setq nmb -1))
+                    ((= nargs 3) 
+                     (setq nmb (arg 3)))
+                    (t (error " wrong number of args to delete "
+                              (cons 'delete (listify nargs)))))
+              (setq val (arg 1) lst (arg 2))
+              (cond ((and (atom lst) (not (null lst)))         
+                     (error " non-list arg to delete " 
+                              (cons 'delete (listify nargs)))))
+              (setq cur (cons nil lst)
+                    ret cur)
+          loop
+              (cond ((or (atom lst) (zerop nmb))
+                     (return (cdr ret)))
+                    ((equal val (car lst))
+                     (rplacd cur (cdr lst))
+                     (setq nmb (1- nmb)))
+                    (t (setq cur (cdr cur))))
+              (setq lst (cdr lst))
+              (go loop))))
+
+;--- delq 
+;  same as delete except eq is used for testing.
+;
+(def delq
+  (lexpr (nargs)
+        (prog (val lst cur ret nmb)
+              (cond ((= nargs 2)
+                     (setq nmb -1))
+                    ((= nargs 3) 
+                     (setq nmb (arg 3)))
+                    (t (error " wrong number of args to delq "
+                              (cons 'delq (listify nargs)))))
+              (setq val (arg 1) lst (arg 2))
+              (cond ((and (atom lst) (not (null lst)))         
+                     (error " non-list arg to delq " 
+                              (cons 'delq (listify nargs)))))
+              (setq cur (cons nil lst)
+                    ret cur)
+          loop
+              (cond ((or (atom lst) (zerop nmb))
+                     (return (cdr ret)))
+                    ((eq val (car lst))
+                     (rplacd cur (cdr lst))
+                     (setq nmb (1- nmb)))
+                    (t (setq cur (cdr cur))))
+              (setq lst (cdr lst))
+              (go loop))))
+
+;--- evenp : num   -  return 
+;
+;
+(def evenp
+  (lambda (n)
+         (cond ((not (zerop (boole 4 1 n))) t))))
+
+;--- ex [name] : unevaluated name of file to edit.
+;      the ex editor is forked to edit the given file, if no
+;      name is given the previous name is used
+;
+(def ex (nlambda (x) (exvi 'ex x nil)))
+
+(declare (special edit_file))
+
+(def exvi 
+  (lambda (cmd x doload) 
+          (prog (handy handyport bigname)
+                (cond ((null x) (setq x (list edit_file)))
+                      (t (setq edit_file (car x))))             
+                (setq bigname (concat (car x) '".l"))
+                (cond ((setq handyport (car (errset (infile bigname) nil)))
+                       (close handyport)
+                       (setq handy bigname))
+                      (t (setq handy (car x))))
+                (setq handy (concat cmd '" " handy))
+                (setq handy (list 'process handy))
+                (eval handy)
+                (cond (doload (load edit_file))))))
+\f
+;--- exec - arg1 [arg2 [arg3 ...] ] unevaluated atoms
+;      A string of all the args concatenated together seperated by 
+;      blanks is forked as a process.
+;
+(def exec
+ (nlambda (list)
+     (do ((xx list (cdr xx))
+         (res "" (concat res " " (car xx))))
+        ((null xx) (*process res)))))
+
+;--- exl - [name] : unevaluated name of file to edit and load.
+;      If name is not given the last file edited will be used.
+;      After the file is edited it will be `load'ed into lisp.
+;
+(def exl (nlambda (x) (exvi 'ex x t)))
+
+;----- explode functions -------
+; These functions, explode , explodec and exploden, implement the 
+; maclisp explode functions completely.
+; They have a similar structure and are written with efficiency, not
+; beauty in mind (and as a result they are quite ugly)
+; The basic idea in all of them is to keep a pointer to the last
+; thing added to the list, and rplacd the last cons cell of it each time.
+;
+;--- explode - arg : lispval
+;      explode returns a list of characters which print would use to
+; print out arg.  Slashification is included.
+;
+(def explode
+  (lambda (arg)
+         (cond ((atom arg) (aexplode arg))
+               ((vectorp arg)
+                (aexplode (concat "vector[" (vsize arg) "]")))
+               ((vectorip arg)
+                (aexplode (concat "vectori[" (vsize-byte arg) "]")))
+               (t (do ((ll (cdr arg) (cdr ll))
+                       (sofar (setq arg (cons '|(| (explode (car arg)))))
+                       (xx))
+                      ((cond ((null ll) (rplacd (last sofar) (ncons '|)| )) 
+                              t)
+                             ((atom ll) (rplacd (last sofar)
+                                                `(| | |.| | | ,@(explode ll) 
+                                                    ,@(ncons '|)|)))
+                              t))
+                       arg)
+                      (setq xx (last sofar)
+                            sofar (cons '| | (explode (car ll))))
+                      (rplacd xx sofar))))))
+
+;--- explodec - arg : lispval
+; returns the list of character which would be use to print arg assuming that
+; patom were used to print all atoms.
+; that is, no slashification would be used.
+;
+(def explodec
+  (lambda (arg)
+         (cond ((atom arg) (aexplodec arg))
+               ((vectorp arg)
+                (aexplodec (concat "vector[" (vsize arg) "]")))
+               ((vectorip arg)
+                (aexplodec (concat "vectori[" (vsize-byte arg) "]")))
+               (t (do ((ll (cdr arg) (cdr ll))
+                       (sofar (setq arg (cons '|(| (explodec (car arg)))))
+                       (xx))
+                      ((cond ((null ll) (rplacd (last sofar) (ncons '|)| )) 
+                              t)
+                             ((atom ll) (rplacd (last sofar)
+                                                `(| | |.| | | ,@(explodec ll) 
+                                                    ,@(ncons '|)|)))
+                              t))
+                       arg)
+                      (setq xx (last sofar)
+                            sofar (cons '| | (explodec (car ll))))
+                      (rplacd xx sofar))))))
+
+;--- exploden - arg : lispval
+;      returns a list just like explodec, except we return fixnums instead
+; of characters.
+;
+(def exploden
+  (lambda (arg)
+         (cond ((atom arg) (aexploden arg))
+               ((vectorp arg)
+                (aexploden (concat "vector[" (vsize arg) "]")))
+               ((vectorip arg)
+                (aexploden (concat "vectori[" (vsize-byte arg) "]")))
+               (t (do ((ll (cdr arg) (cdr ll))
+                       (sofar (setq arg (cons 40. (exploden (car arg)))))
+                       (xx))
+                      ((cond ((null ll) (rplacd (last sofar) (ncons 41.)) 
+                              t)
+                             ((atom ll) (rplacd (last sofar)
+                                                `(32. 46. 32. ,@(exploden ll) 
+                                                    ,@(ncons 41.)))
+                              t))
+                       arg)
+                      (setq xx (last sofar)
+                            sofar (cons 32. (exploden (car ll))))
+                      (rplacd xx sofar))))))
+\f
+;-- expt  - x
+;        - y
+;
+;         y
+; returns x
+;
+(defun expt (x y)
+  (cond ((equal x 1) x)
+       ((zerop x) x)   ; Maclisp does this 
+       ((lessp y 0) (quotient 1.0 (expt x (times -1 y))))
+       ((floatp y) 
+        (exp (times y (log x)))) ; bomb out for (-3)^4 or (-3)^4.0 or 0^y.
+       ((bigp y)
+        (error "expt: Can't compute number to a bignum power" y))
+       (t ; y is integer, y>= 0
+          (prog (res)
+                (setq res 1)
+                loop
+                (cond ((equal y 0) (return res))
+                      ((oddp y)(setq res (times  res x) y (1- y)))
+                      (t (setq x (times x x) y (/ y 2))))
+                (go loop)))))
+
+
+
+;--- ffasl :: fasl in a fortran file
+;  arg #
+;   1  - fnam : file name
+;   2  - entry : entry point name
+;   3  - fcn  : entry name
+;   4   - disc : optional discipline
+;   5   - lib  ; optional library specifier
+;
+(defun ffasl (fnam entry fcn &optional (disc 'subroutine) (lib " "))
+  (cfasl fnam entry fcn disc (concat lib " -lI77 -lF77 -lm")))
+
+
+;
+; filepos function (maclisp compatibility)
+;
+(defun filepos n
+  (cond ((zerop n) nil)
+       ((onep n)
+        (fseek (arg 1) 0 1))
+       ((equal n 2)
+        (fseek (arg 1) (arg 2) 0))))
+
+;--- fixp - l : lispval
+;      returns t if l is a fixnum or bignum
+;
+(defun fixp (x) (or (equal (type x) 'fixnum)
+                   (equal (type x) 'bignum)))
+
+
+
+;--- flatsize - l : lispval
+;           the second arg should be:
+;            - n : limit for what we care about
+;           but we dont care about this at present, since we have
+;           to explode the whole thing anyway.
+;      returns the number of characters which print would
+;      use to print l
+;
+(defun flatsize n
+  (length (explode (arg 1))))
+
+
+;--- floatp - l : lispval
+;      returns t if l is a flonum
+;
+(defun floatp (x) (equal 'flonum (type x)))
+
+
+;--- getchar,getcharn   - x : atom
+;                      - n : fixnum
+; returns the n'th character of x's pname (the first corresponds to n=1)
+; if n is negative then it counts from the end of the pname
+; if n is out of bounds, nil is returned
+
+(def getchar
+  (lambda (x n)
+         (concat (substring x n 1))))
+
+
+(def getcharn
+  (lambda (x n)
+         (substringn x n 0)))
+
+
+(def getl 
+  (lambda (atm lis)
+         (do ((ll (cond ((atom atm) (plist atm))
+                        (t (cdr atm)))
+                  (cddr ll)))
+             ((null ll) nil)
+             (cond ((memq (car ll) lis) (return ll))))))
+
+
+;--- help
+; retrive selected portions of the Franz Lisp manual.
+; There are four types of help offered:
+; (help) prints a description of the other three options
+; (help tc) prints a table of contents.
+; (help n) {where n is a number or b or c} prints the whole chapter.
+; (help fcn) prints info on function fcn
+;
+; An index to the functions is kept in the documentation directory.
+; The index has entries like (append ch2.r).  
+; When asked to print info on a function, it locates the chapter
+; using the index then asks more to locate the definition.
+;
+(declare (localf locatefunction))
+
+(defun help fexpr (lis)
+  (cond ((null lis) 
+ (patom "type (help fnc) for info on function fnc")(terpr)
+ (patom "type (help n) to see chapter n")(terpr)
+ (patom "type (help tc) for a table of contents")(terpr))
+       (t (do ((ll lis (cdr ll))
+               (fcn))
+              ((null ll))
+              (cond ((not (atom (setq fcn (car ll))))
+                     (patom "Bad option to help ")(print fcn)(terpr))
+                    ((and (stringp fcn) (setq fcn (concat fcn)) nil))
+                    ((eq fcn 'tc)
+                     (patom "Table of contents")(terpr)
+ (patom "1 - intro; 2 - data structure; 3 - arithmetic; 4 - special")(terpr)
+ (patom "5 - i/o; 6 - system; 7 - reader; 8 - functions; 9 - arrays")(terpr)
+ (patom "10 - exceptions; 11 - trace package; 12 - Liszt;")(terpr)
+ (patom "14 - step package; 15 - fixit package") (terpr)
+ (patom "b - special symbols; c - gc & debugging & top level ")(terpr))
+                    ((or (and (numberp fcn) (lessp fcn 16) (greaterp fcn -1))
+                         (memq fcn '(b c)))
+                     (apply 'process 
+                        (ncons (concat "/usr/ucb/ul "
+                                       lisp-library-directory
+                                       "/manual/ch"
+                                      fcn ".r | /usr/ucb/more -f" ))))
+                    ((locatefunction fcn))
+                    (t (patom "Unknown function: ")(print fcn)(terpr)))))))
+
+(declare (special readtable))
+
+(defun locatefunction (fc)
+  (let (x inf )
+       (cond ((null (get 'append 'helplocation)) 
+             (patom "[Reading help index]")(drain)
+             (setq inf (infile (concat lisp-library-directory
+                                       "/manual/helpindex")))
+             (do ((readtable (makereadtable t))
+                  (x (read inf) (read inf)))
+                 ((null x) (close inf) (terpr))
+                 (cond ((null (cddr x))
+                        (putprop (car x) (cadr x) 'helplocation))
+                       (t (putprop (concat (car x) " " (cadr x))
+                                   (caddr x)
+                                   'helplocation))))))
+       (cond ((setq x (get fc 'helplocation))
+             (apply 'process (ncons (concat "/usr/ucb/ul "
+                                            lisp-library-directory
+                                            "/manual/"
+                                            x 
+                                            " | /usr/ucb/more -f \"+/(" 
+                                            fc 
+                                            "\"")))
+             t))))
+
+;
+; (hunk 'g_arg1 [...'g_argn])
+;
+; This function makes a hunk. The hunk is preinitialized to the
+; arguments present. The size of the hunk is determined by the
+; number of arguments present.
+;
+
+(defun hunk n
+  (prog (size)
+       (setq size -1)
+       (cond ((> n 128) (error "hunk: size is too big" n))
+             ((eq n 1) (setq size 0))
+             ((eq n 0) (return nil))   ; hunk of zero length
+             (t (setq size (1- (haulong (1- n))))))
+       (setq size (*makhunk size))
+       (do
+        ((argnum 0 (1+ argnum)))
+        ((eq argnum n))
+        (*rplacx argnum size (arg (1+ argnum))))
+       (return size)))
+
+
+;--- last - l : list
+;      returns the last cons cell of the list, NOT the last element
+;
+(def last 
+  (lambda (a)
+         (do ((ll a (cdr ll)))
+             ((null (cdr ll))  ll))))
+
+;---- load 
+; load will either load (read-eval)  or fasl in the file.
+; it is affected by these global flags
+;  tilde-expansion :: expand filenames preceeded by ~ just like
+;      csh does (we do the expansion here so each i/o function we call
+;      doesn't have to do it).
+;  load-most-recent :: if there is a choice between a .o and a .l file,
+;      load the youngest one
+;
+(declare (localf load-a-file))
+(declare (special gcdisable load-most-recent tilde-expansion))
+
+(or (boundp 'load-most-recent) (setq load-most-recent nil))
+(or (boundp 'tilde-expansion) (setq tilde-expansion t))
+
+(defun load (filename &rest fasl-args)
+  (cond ((not (or (symbolp filename) (stringp filename))) 
+        (error "load: illegal filename " filename)))
+  (let ( load-only fasl-only no-ext len search-path name pred shortname explf
+        faslfile loadfile)
+
+       
+       (cond (tilde-expansion (setq filename (tilde-expand filename))))
+               
+       ; determine the length of the filename, ignoring the possible
+       ; list of directories.  set explf to the reversed exploded filename
+       (setq len (do ((xx (setq explf (nreverse (exploden filename))) (cdr xx))
+                     (i 0 (1+ i)))
+                    ((null xx) i)
+                    (cond ((eq #// (car xx)) (return i)))))
+
+       (cond ((> len 2)
+             (cond ((eq (cadr explf) #/.)
+                    (cond ((eq (car explf) #/o)
+                           (setq fasl-only t))
+                          ((eq (car explf) #/l)
+                           (setq load-only t))
+                          (t (setq no-ext t))))
+                   (t (setq no-ext t))))
+            (t (setq no-ext t)))
+
+       ; a short name is less or equal 12 characters.  If a name is not
+       ; short, then load will not try to append .l or .o
+       (cond ((or (< len 13) (status feature long-filenames))
+             (setq shortname t)))
+
+       (cond ((and (> len 0) (eq (getchar filename 1) '/))
+             (setq search-path '(||)))
+            (t (setq search-path (status load-search-path))))
+       (do ((xx search-path (cdr xx)))
+          ((null xx) (error "load: file not found " filename))
+          (setq pred (cond ((memq (car xx) '(|| |.|)) '||)
+                           (t (concat (car xx) "/"))))
+          (cond (no-ext
+                 (cond ((and shortname
+                             load-most-recent
+                             (probef
+                                (setq faslfile (concat pred filename ".o")))
+                             (probef
+                                (setq loadfile (concat pred filename ".l"))))
+                        ; both an object and a source file exist.
+                        ; load the last modified one (fasl wins in ties)
+                        (let ((faslstat (filestat faslfile))
+                              (loadstat (filestat loadfile)))
+                           (cond ((< (filestat:mtime faslstat)
+                                     (filestat:mtime loadstat))
+                                  (return (load-a-file loadfile)))
+                                 (t (return
+                                       (fasl-a-file faslfile
+                                                    (car fasl-args)
+                                                    (cadr fasl-args)))))))
+                       ((and shortname
+                             (probef (setq name
+                                           (concat pred filename ".o"))))
+                        (return (fasl-a-file name (car fasl-args)
+                                             (cadr fasl-args))))
+                       ((and shortname
+                             (probef (setq name
+                                           (concat pred filename ".l"))))
+                        (return (load-a-file name)))
+                       ((probef (setq name (concat pred filename)))
+                        (cond (fasl-args (return
+                                            (fasl-a-file name
+                                                         (car fasl-args)
+                                                         (cadr fasl-args))))
+                              (t (return (load-a-file name)))))))
+                (fasl-only
+                 (cond ((probef (setq name (concat  pred  filename)))
+                        (return (fasl-a-file name (car fasl-args)
+                                             (cadr fasl-args))))))
+                (load-only
+                 (cond ((probef (setq name (concat pred filename)))
+                        (return (load-a-file name)))))))))
+
+;--- tilde-expand :: given a ~filename, expand it
+;
+(defun tilde-expand (name)
+   (cond ((or (symbolp name) (stringp name))
+         (cond ((eq (getcharn name 1) #/~)
+                (let ((form (exploden name)))
+                   (do ((xx (cdr form) (cdr xx))
+                        (res)
+                        (val))
+                       ((or (null xx) (eq (car xx) #//))
+                        ;; if this is the current user, just get value
+                        ;; from environment variable HOME
+                        (cond ((or (null res)
+                                   (equal (setq res (implode (nreverse res)))
+                                          (getenv 'USER)))
+                               (setq val (getenv 'HOME)))
+                              (t (setq val (username-to-dir res))))
+                        (cond ((null val)
+                               (error "tilde-expand: unknown user " res))
+                              (t (concat val (implode xx)))))
+                       (setq res (cons (car xx) res)))))
+               (t name)))
+        (t (error "tilde-expand: illegal argument " name))))
+
+      
+
+;--- fasl-a-file
+; The arguments are just like those to fasl.  This fasl's a file
+; and if the translink's are set, it does the minimum work necessary to rebind
+; the links (so that the new functions just fasl'ed in will be used).
+; 
+(defun fasl-a-file (name map warnflag)
+   (let ((translinkarg (status translink)))
+      (prog1
+        (fasl name map warnflag)
+        (cond ((and translinkarg (setq translinkarg (status translink)))
+               ; if translink was set before and is still set
+               (cond ((eq translinkarg t)
+                      (sstatus translink nil)  ; clear all links
+                      (sstatus translink t))   ; set to make links
+                     (t ; must be 'on'
+                        (sstatus translink on) ; recompute all links
+                        ))))))) 
+
+(declare (special $ldprint))   ; print message before loading
+(declare (special prinlevel prinlength))
+
+(defun load-a-file (fname)
+   (cond ($ldprint (patom "[load ")(patom fname)(patom "]")(terpr)))
+   (let ((translinkarg (status translink)))
+      (prog1
+        (let ((Piport (infile fname))
+              ; (gcdisable t)  ; too dangerous: removed for now
+              ; don't gc when loading, it slows things down
+              (eof (list nil)))
+           (do ((form (errset (read Piport eof)) (errset (read Piport eof)))
+                (lastform "<no form read successfully>"))
+               ((eq eof (car form)) (close Piport) t)
+               (cond ((null form)
+                      (error "load aborted due to read error after form "
+                             lastform))
+                     (t (setq lastform (car form))
+                        (eval (car form))))))
+        (cond ((and translinkarg (setq translinkarg (status translink)))
+               ; if translink was set before and is still set
+               (cond ((eq translinkarg t)
+                      (sstatus translink nil)  ; clear all links
+                      (sstatus translink t))   ; set to make links
+                     (t ; must be 'on'
+                        (sstatus translink on) ; recompute all links
+                        )))))))
+
+(funcall 'sstatus (list 'load-search-path (list '|.| lisp-library-directory)))
+;--- include - read in the file name given, the name not evaluated
+;
+(def include (nlambda (l) (load (car l))))
+
+;--- includef - read in the file name given and eval the first arg
+;
+(def includef (lambda (l) (load l)))
+
+
+;--- list-to-bignum
+;  convert a list of fixnums to a bignum.
+; there is a function bignum-to-list but it is written in C
+;
+;(author: kls)
+;
+(def list-to-bignum
+ (lambda (x) (cond (x (scons (car x) (list-to-bignum (cdr x))))
+                  (t nil))))
+
+\f
+
+;--- macroexpand - form 
+;      expands out all macros it can
+;
+(def macroexpand
+  (lambda (form)
+    (prog nil
+  top (cond ((atom form) (return form))
+           ((atom (car form))
+            (return
+             (let ((nam (car form)) def disc)
+                  (setq def (getd nam))
+                  (setq disc (cond ((bcdp def) (getdisc def))
+                                   ((arrayp def) 'array)
+                                   ((dtpr def) (car def))))
+                  (cond ((and (null def)
+                              (get nam 'macro-autoload))
+                         (setq disc 'macro)))
+                  (cond ((memq disc '(array lambda lexpr nil))
+                         (cons nam (mapcar 'macroexpand (cdr form))))
+                        ((eq disc 'macro)
+                         (setq form (apply nam form))
+                         (go top))
+                        ((eq nam 'prog)
+                         (cons nam
+                               (cons (cadr form)
+                                     (mapcar 'macroexpand (cddr form)))))
+                        (t form)))))
+           (t (return (cons (macroexpand (car form))
+                            (mapcar 'macroexpand (cdr form)))))))))
+
+
+
+
+;
+; (makhunk 'n)
+;
+; This function is similar to hunk, except that:
+;
+; n can be a fixnum, which specifies the length of the hunk.
+;      The hunk is preinitialized to nil's
+; n can be a list which is used to preinitialize the hunk.
+;
+(defun makhunk (n)
+  (prog (size Hunk)
+       (setq size -1)
+       (cond ((numberp n)
+;
+; If n is a number then build a nil hunk of the right size
+;
+              (cond ((greaterp n 128) (error "makhunk: size is too big" n))
+                    ((= n 1) (setq size 0))
+                    (t (setq size (1- (haulong (1- n))))))
+              (cond ((minusp size) (return nil)))
+              (setq Hunk (*makhunk size))
+              (do ((i 0 (1+ i)))
+                  ((=& i n))
+                  (*rplacx i Hunk nil))
+              (return Hunk))
+;
+; If it isn't a number, then try hunk on it
+;
+             (t (return (apply 'hunk n))))))
+
+;--- member - VAL : lispval
+;          - LIS : list
+;      returns that portion of LIS beginning with the first occurance
+;      of VAL  if  VAL is found at the top level of list LIS.
+;      uses equal for comparisons.
+;
+(def member 
+  (lambda ($a$ $l$)
+         (do ((ll $l$ (cdr ll)))
+             ((null ll) nil)
+             (cond ((equal $a$ (car ll)) (return ll))))))
+
+;--- memq - arg : (probably a symbol)
+;        - lis : list
+; returns part of lis beginning with arg if arg is in lis
+;      
+; [ defintion moved to top of file to allow backquote macro to work ]
+
+;--- min - arg1 ... numbers 
+;
+;      returns minimum of n numbers. 
+;
+
+(def min
+  (lexpr (nargs)
+        (do ((i nargs (1- i))
+             (min (arg 1)))
+            ((lessp i 2) min)
+            (cond ((lessp (arg i) min) (setq min (arg i)))))))
+\f
+
+;
+(def oddp
+  (lambda (n)
+         (cond ((not (zerop (boole 1 1 n))) t))))
+
+;--- plusp : x - number
+; returns t iff x is greater than zero
+
+(def plusp
+  (lambda (x)
+         (greaterp x 0)))
+
+
+;--- princ : l - any s-expression
+;          [p] - port to write to
+; prints using patom for atoms (unslashified)
+;
+(def princ
+  (lexpr (n)
+        (prog (port val)
+              (cond ((eq n 2) (setq port (arg 2))))
+              (cond ((dtpr (setq val (arg 1)))
+                     (cond ((and (eq 'quote (car val))
+                                 (dtpr (cdr val))
+                                 (null (cddr val)))
+                            (patom "'" port)
+                            (princ (cadr val) port))
+                           (t 
+                            (patom "(" port)
+                            (do ((xx val))
+                                ((null xx) (patom ")" port))
+                                (princ (car xx) port)
+                                (cond ((null (setq xx (cdr xx))))
+                                      ((not (dtpr xx))
+                                       (patom " . " port)
+                                       (princ xx port)
+                                       (setq xx nil))
+                                      (t (patom " " port)))))))
+                    (t (patom val port)))
+              (return t))))
+
+;--- prog1 : return the first value computed in a list of forms
+;
+(def prog1
+  (lexpr (n)
+        (arg 1)))
+
+;--- reverse : l - list
+;      returns the list reversed using cons to create new list cells.
+;
+(def reverse 
+  (lambda (x)
+         (cond ((null x) nil)
+               (t (do ((cur (cons (car x) nil) 
+                            (cons (car res) cur))
+                       (res (cdr x) (cdr res)))
+                      ((null res) cur))))))
+
+
+;--- shell - invoke a new c shell
+;
+(def shell 
+  (lambda nil 
+         ((lambda (shellname)
+                  (cond ((lessp (flatc shellname) 1) (setq shellname 'csh)))
+                  (apply 'process (ncons shellname)))
+          (getenv 'SHELL))))
+
+
+
+; S L O A D  stuff
+;
+(defvar $sldprint t)
+(declare (special sload-print))
+(setq sload-print nil)
+
+(defmacro sl-print (&rest args)
+   `(cond ((and sload-print
+               (getd sload-print))
+          (funcall sload-print . ,args))
+         (t (print . ,args))))
+
+;--- sload : fn - file name (must include the .l)
+;      loads in the file printing each result as it is seen
+;
+(defun sload (&rest files)
+   (mapc '(lambda (fn)
+            (prog (por eof argnum result)
+               (cond ((setq por (infile fn))
+                      (and $sldprint
+                           (progn (princ "[sload ")
+                                  (princ fn)
+                                  (princ "]")
+                                  (terpr))))
+                     (t (patom "bad file name: ")
+                        (patom fn)
+                        (terpr)
+                        (return nil)))
+               (setq eof (gensym))
+               (do ((input (read por eof) (read por eof)))
+                   ((eq eof input) (close por))
+                   (and $sldprint
+                        (cond ((and (dtpr input)
+                                    (setq argnum
+                                          (get (car input) 'sloadprintarg)))
+                               (print (nth argnum input)))
+                              (t (print input))))
+                   (setq result (eval input))
+                   (and (eq 'value $sldprint)
+                        (progn (princ ": ")
+                               (sl-print result)))
+                   (and $sldprint
+                        (terpr)))
+               (return t)))
+        files))
+
+(defprop def 1 sloadprintarg)
+(defprop defun 1 sloadprintarg)
+
+(defprop setq 1 sloadprintarg)
+(defprop declare 1 sloadprintarg)
+
+
+\f
+
+
+;---- bubble merge sort 
+; it recursively splits the list to sort until the list is small.  At that
+; point it uses a bubble sort.  Finally the sorted lists are merged.
+
+(declare (special sort-function))
+
+;--- sort :: sort a lisp list
+; args: lst - list of items
+;       fcn - function to compare two items.
+; returns: the list with such that for each pair of adjacent elements,
+;         either the elements are equal, or fcn applied to the two 
+;         args returns a non nil value.
+;
+(defun sort (lst fcn)
+  (setq sort-function (cond (fcn)   ; store function name in global cell
+                           (t 'alphalessp)))
+  ; (setq sort-compares 0)             ; count number of comparisons
+  (sortmerge lst (length lst)))
+
+
+;--- sortmerge :: utility routine to sort
+; args: lst - list of items to sort
+;      nitems - a rough idea of how many items are in the list
+;
+; result - sorted list (see the result of sort above)
+;
+(defun sortmerge (lst nitems)
+  (prog (tmp tmp2)
+       (cond ((greaterp nitems 7)
+              ; do a split and merge
+              (setq tmp (splitlist lst (setq tmp2 (quotient nitems 2))))
+              (return (mergelists (sortmerge (car tmp) tmp2)
+                             (sortmerge (cdr tmp) tmp2))))
+             (t ; do a bubble sort
+                (do ((l lst (cdr l))
+                     (fin))
+                    ((null l))
+                    (do ((ll lst (cdr ll)))
+                        ((eq fin (cdr ll)) (setq fin ll))
+                        ;(setq sort-compares (1+ sort-compares))
+                        (cond ((not (funcall sort-function (car ll) (cadr ll)))
+                               (rplaca ll (prog1 (cadr ll)
+                                                (rplaca (cdr ll)
+                                                        (car ll))))))))
+                (return lst)))))
+
+;--- splitlist :: utility routine to split a list
+; args : lst - list to split
+;        spliton - number of items to put in the first list
+;
+; returns: a cons cell whose car is the first part of the list
+;         and whose cdr is the second part.
+;
+(defun splitlist (lst spliton)
+  (prog (second)
+       (do ((i spliton (sub1 i))
+            (l lst))
+           ((or (null (cdr l)) (zerop i))
+            (setq second (cdr l))
+            (rplacd l nil))
+           (setq l (cdr l)))
+       (return (cons lst second))))
+
+
+;--- mergelists ::utility routine to merge two lists based on predicate function
+; args: ls1 - lisp list
+;      ls2 - lisp list
+;      sort-function (global) - compares items of the lists
+;
+; returns: a sorted list containing the elements of the two lists.
+; 
+(defun mergelists  (ls1 ls2)
+  (prog (result current)
+       ; initialize
+       (setq current (setq result (cons nil nil)))
+loop   (cond ((null ls1)
+              (rplacd current ls2)
+              (return (cdr result)))
+             ((null ls2)
+              (rplacd current ls1)
+              (return (cdr result)))
+             ((funcall sort-function (car ls1) (car ls2))
+              ;(setq sort-compares (1+ sort-compares))
+              (rplacd current ls1)
+              (setq current ls1
+                    ls1 (cdr ls1)))
+             (t ;(setq sort-compares (1+ sort-compares))
+                (rplacd current ls2)
+                (setq current ls2
+                      ls2 (cdr ls2))))
+       (go loop)))
+
+;--- end bubble merge sort
+(declare (localf exchange2))
+
+(defun sortcar (a fun)
+   (prog (n)
+       (if (null fun) then (setq fun 'alphalessp))
+       (cond ((null a) (return nil)) ;no elements
+            (t (setq n (length a))
+               (do i 1 (1+ i) (greaterp i n) (sortcarhelp a fun))
+               (return a)))))
+
+(defun sortcarhelp (a fun)
+  (cond ((null (cdr a)) a)
+        ((funcall fun (caadr a) (caar a))  
+        (exchange2 a)
+        (sortcarhelp (cdr a) fun))
+       (t (sortcarhelp (cdr a) fun))))
+
+
+(defun exchange2 (a)
+  (prog (temp)
+       (setq temp (cadr a))
+       (rplaca (cdr a) (car a))
+       (rplaca a temp)))
+
+;--- sublis: alst - assoc list ((a . val) (b . val2) ...)
+;           exp  - s-expression
+; for each atom in exp which corresponds to a key in alst, the associated
+; value from alst is substituted.  The substitution is done by adding
+; list cells, no struture mangling is done.  Only the minimum number
+; of list cells will be created.
+;
+(def sublis
+  (lambda (alst exp)
+     (let (tmp)
+         (cond ((atom exp) 
+                (cond ((setq tmp (assoc exp alst))
+                       (cdr tmp))
+                      (t exp)))
+               ((setq tmp (sublishelp alst exp))
+                (car tmp))
+               (t exp)))))
+
+;--- sublishelp : alst - assoc list
+;                exp  - s-expression
+; this function helps sublis work.  it is different from sublis in that
+; it return nil if no change need be made to exp, or returns a list of
+; one element which is the changed exp.
+;
+(def sublishelp
+  (lambda (alst exp)
+     (let (carp cdrp)
+         (cond ((atom exp)
+                (cond ((setq carp (assoc exp alst))
+                       (list (cdr carp)))
+                      (t nil)))
+               (t (setq carp (sublishelp alst (car exp))
+                        cdrp (sublishelp alst (cdr exp)))
+                  (cond ((not (or carp cdrp)) nil)             ; no change
+                        ((and carp (not cdrp))                 ; car change
+                         (list (cons (car carp) (cdr exp))))   
+                        ((and (not carp) cdrp)                 ; cdr change
+                         (list (cons (car exp) (car cdrp))))   
+                        (t                                     ; both change 
+                         (list (cons (car carp) (car cdrp))))))))))
+
+\f
+;--- subst : new - sexp
+;           old - sexp
+;           pat - sexp
+; substitutes in patrn all occurrences equal to old with new and returns the
+; result
+; MUST be put in the manual
+
+(declare (special new old))
+
+(def subst 
+  (lambda (new old pat)
+         (cond ((symbolp old) (substeq pat))
+               (t (substequal pat)))))
+
+;use this function for substituting for symbols
+(def substeq
+  (lambda (pat)
+         (cond ((eq old pat) new)
+               ((atom pat) pat)
+               (t (cons (substeq (car pat))(substeq (cdr pat)))))))
+
+(def substequal
+  (lambda (pat)
+         (cond ((equal old pat) new)
+               ((atom pat) pat)
+               (t (cons (substequal (car pat))
+                        ; in interlisp, the next line would be
+                        ;(substeq (cdr pat))
+                        ; for maclisp compatibility, we do this.
+                        (substequal (cdr pat)))))))
+
+(declare (unspecial new old))
+;--- vi: arg is unevaluated name of function to run vi on
+;
+(def vi (nlambda (x) (exvi 'vi x nil)))
+
+;--- vil : arg is unevaluated, edits file and then loads it
+;
+(def vil (nlambda (x) (exvi 'vi x t)))
+
+;--- *quo : returns integer part of x/y
+; x and y must be fixnums.
+;
+(putd '*quo (getd 'quotient))
+
+;--- xcons : a - sexp
+;           b - sexp
+; returns (b . a)   that is, it is an exchanged cons
+;
+(def xcons  (lambda (a b) (cons b a)))
+
+
+
+
+
+
+;--- mode lines, must be last lines of the file
+; vi: set lisp :
+;
diff --git a/usr/src/ucb/lisp/lisplib/common2.l b/usr/src/ucb/lisp/lisplib/common2.l
new file mode 100644 (file)
index 0000000..eeda8be
--- /dev/null
@@ -0,0 +1,884 @@
+(setq rcs-common2-
+   "$Header: common2.l,v 1.7 83/09/12 15:23:23 layer Exp $")
+
+;;
+;; common2.l                           -[Sat Aug 13 12:55:56 1983 by jkf]-
+;;
+;; lesser used functions
+;;
+
+
+(declare (macros t))
+
+;--- process functions
+; these functions permit the user to start up processes and either
+; to either wait for their completion or to continue processing,
+; communicating with them through a pipe.
+;
+; the main function, *process, is written in C.  These functions
+; handle the common cases
+;
+;--- *process-send  :: start a process and return port to write to
+;
+(defun *process-send (command)
+   (cadr (*process command nil t)))
+
+;--- *process-receive :: start a process and return port to read from
+;
+(defun *process-receive (command)
+   (car (*process command t)))
+
+;--- process :: the old nlambda version of process
+;  this function is kept around for compatibility
+; use: (process command [frompipe [topipe]])
+;  if the from and to pipes aren't given, run it and wait
+;
+(defun process fexpr (args)
+   (declare (*args 1 3))
+   (let ((command (car args))
+        (fromport (cadr args))
+        (toport (caddr args)))
+      (cond ((null (cdr args)) (*process command))  ; call and wait
+           (t (let ((res (*process command fromport toport)))
+                 (cond (fromport (set fromport (cadr res))))
+                 (cond (toport (set toport (car res))))
+                 ; return pid
+                 (caddr res))))))
+
+
+;--- msg : print a message consisting of strings and values
+; arguments are:
+;   N      - print a newline
+;   (N foo) - print foo newlines (foo is evaluated)
+;   B       - print a blank
+;   (B foo) - print foo blanks (foo is evaluated)
+;   (P foo) - print following args to port foo (foo is evaluated)
+;   D      - drain
+;   other   - evaluate a princ the result (remember strings eval to themselves)
+
+(defmacro msg (&rest msglist)
+  (do ((ll msglist (cdr ll))
+       (result)
+       (cur nil nil)
+       (curport nil)
+       (current))
+      ((null ll) `(progn ,@(nreverse result)))
+      (setq current (car ll))
+      (If (dtpr current)
+         then (If (eq (car current) 'N)
+                  then (setq cur `(msg-tyo-char 10 ,(cadr current)))
+               elseif (eq (car current) 'B)
+                  then (setq cur `(msg-tyo-char 32 ,(cadr current)))
+               elseif (eq (car current) 'P)
+                  then (setq curport (cadr current))
+               else (setq cur `(msg-print ,current)))
+       elseif (eq current 'N)
+         then (setq cur (list 'terpr))         ; (can't use backquote
+       elseif (eq current 'B)                  ; since must have new
+         then (setq cur (list 'tyo 32))        ; dtpr cell at end)
+       elseif (eq current 'D)
+         then (setq cur '(drain))
+       else (setq cur `(msg-print ,current)))
+      (If cur 
+         then (setq result (cons (If curport then (nconc cur (ncons curport))
+                                             else cur)
+                                 result)))))
+
+(defun msg-tyo-char (ch n &optional (port nil))
+  (do ((i n (1- i)))
+      ((< i 1))
+      (cond ((eq ch 10) (terpr port))
+           (t (tyo ch port)))))
+
+(defun msg-print (item &optional (port nil))
+   (patom item port))
+
+;--- printblanks :: print out a stream of blanks to the given port
+; (printblanks 'x_numberofblanks 'p_port)
+;
+(def printblanks
+   (lambda (n prt)
+      (let ((easy (memq n '( 0  ""
+                            1  " "
+                            2  "  "
+                            3  "   "
+                            4  "    "
+                            5  "     "
+                            6  "      "
+                            7  "       "
+                            8  "        "))))
+        (cond (easy (patom (cadr easy) prt))
+              (t (do ((i n (1- i)))
+                     ((<& i 1))
+                     (patom " " prt)))))))
+
+
+
+
+
+; --- linelength [numb]
+;
+; sets the linelength (actually just varib linel) to the
+; number given: numb
+; if numb is not given, the current line length is returned
+; 
+
+(declare (special linel))
+
+(setq linel 80)
+
+(def linelength
+     (nlambda (form)
+             (cond ((null form) linel )
+                   ((numberp (car form)) (setq linel (car form)))
+                   (t linel))))
+
+; ========================================
+;
+;      (charcnt port) 
+; returns the number of characters left on the current line
+; on the given port
+;
+; =======================================
+
+
+(def charcnt
+     (lambda (port) (- linel (nwritn port))))
+
+;--- nthcdr :: do n cdrs of the list and return the result
+;
+; 
+(defun nthcdr (index list)
+   (cond ((fixp index)
+         (cond ((<& index 0)
+                (cons nil list))
+               ((=& index 0)
+                list)
+               (t (nthcdr (1- index) (cdr list)))))
+        (t (error "Non fixnum first argument to nthcdr " index))))
+
+;--- nthcdr (cmacro) :: version of nthcdr for use by the compiler
+;
+(defcmacro nthcdr (index list)
+   (if (and (fixp index) (=& index 0))
+      then list        ; (nthcdr 0 expr) => expr
+      else (let ((val (assq index '((1  . cdr)
+                                   (2  . cddr)
+                                   (3  . cdddr)
+                                   (4  . cddddr)
+                                   (5  . cdddddr)
+                                   (6  . cddddddr)))))
+             (cond (val `(,(cdr val) ,list))   ; (nthcdr 1-6 list)
+                   (t `(nthcdr ,index ,list)))))) ; other cases
+
+
+;--- nth :: return nth element of the list
+; cdr index times and then car to get the element.
+; thus the first element is 0
+;
+(defun nth (index list)
+   (car (nthcdr index list)))
+
+;--- nth (cmacro) :: compiler macro to do the same thing
+;
+(defcmacro nth (index list)
+   `(car (nthcdr ,index ,list)))
+
+   
+
+
+;;==============================
+;  (assqr val alist)
+; acts much like assq, it looks for val in the cdr of elements of
+; the alist and returns the element if found.
+; fix this when the compiler works
+(eval-when nil (def assqr 
+    (lambda (val alist)
+       (do ((al alist (cdr al)))
+           ((null al) nil)
+           (cond ((eq val (cdar al)) (return (car al))))))))
+
+
+; ====================
+; (listp 'x) is t if x is a non-atom or nil
+; ====================
+(def listp (lambda (val) (or (dtpr val) (null val))))
+
+
+
+;--- memcar - VAL : lispval
+;          - LIS : list
+;      returns t if VAL found as the car of a top level element.
+;temporarily turn this off till the compiler can handle it.
+(eval-when nil (def memcar 
+  (lambda (a l)
+         (do ((ll l (cdr ll)))
+             ((null ll) nil)
+             (cond ((equal (caar ll) a) (return (cdar ll))))))))
+\f
+; =================================
+;
+;      (memcdr 'val 'listl)
+;
+; the list listl is searched for a list
+; with cdr equal to val. if found, the
+; car of that list is returned.
+; ==================================
+;fix this when compiler works ok
+(eval-when nil (def memcdr 
+  (lambda (a l)
+         (do ((ll l (cdr ll)))
+             ((null ll) nil)
+             (cond ((equal (cdar ll) a) (return (caar l))))))))
+
+
+;this looks like funcall, so we will just use it
+'(def apply* 
+  (nlambda ($x$)
+       (eval (cons (eval (car $x$)) (cdr $x$)))))
+
+(putd 'apply* (getd 'funcall))
+
+(defun remq (item list &optional (cnt -1))     ;no tail recursion sucks.
+   (let ((head nil)
+        (tail nil))
+      (do ((l list (cdr l))
+          (newcell))
+         ((null l) head)
+         (cond ((or (not (eq (car l) item))
+                    (=& 0 cnt))
+                (setq newcell (list (car l)))
+                (cond ((null head) (setq head newcell))
+                      (t (rplacd tail newcell)))
+                (setq tail newcell))
+               (t (setq cnt (1- cnt)))))))
+
+(defun tab n
+   (prog (nn prt over)
+      (setq nn (arg 1))
+      (cond ((>& n 1) (setq prt (arg 2))))
+      (cond ((>& (setq over (nwritn prt)) nn)
+            (terpri prt)
+            (setq over 0)))
+      (printblanks (- nn over) prt)))
+
+;--- charcnt :: returns the number of characters left on the current line
+;      p - port
+;(local function)
+(def charcnt
+     (lambda (port) (- linel (nwritn port))))
+
+;(local function)
+;
+(declare (special $outport$))
+(def $patom1 (lambda (x) (patom x $outport$)))
+
+;;; --- cmu  functions ---
+(def attach
+   (lambda (x y)
+          (cond ((dtpr y) (rplacd y (cons (car y) (cdr y))) (rplaca y x))
+                (t (error "An atom can't be attached to " y)))))
+(def Cnth
+   (lambda (x n)
+          (cond ((> 1 n) (cons nil x))
+                (t
+                   (prog nil
+                    lp   (cond ((or (atom x) (eq n 1)) (return x)))
+                         (setq x (cdr x))
+                         (setq n (1- n))
+                         (go lp))))))
+
+
+
+
+(def dsubst
+   (lambda (x y z)
+          (prog (b)
+                (cond ((eq y (setq b z)) (return (copy x))))
+                lp
+                (cond ((atom z) (return b))
+                      ((cond ((symbolp y) (eq y (car z))) (t (equal y (car z))))
+                       (rplaca z (copy x)))
+                      (t (dsubst x y (car z))))
+                (cond ((and y (eq y (cdr z))) (rplacd z (copy x)) (return b)))
+                (setq z (cdr z))
+                (go lp))))
+
+(putd 'eqstr (getd 'equal))
+
+(defun insert (x l comparefn nodups)
+      (cond ((null l) (list x))
+            ((atom l) (error "an atom, can't be inserted into" l))
+            ((and nodups (member x l)) l)
+           (t (cond
+                ((null comparefn) (setq comparefn (function alphalessp))))
+               (prog (l1 n n1 y)
+                     (setq l1 l)
+                     (setq n (length l))
+                a    (setq n1 (/ (add1 n) 2))
+                     (setq y (Cnth l1 n1))
+                     (cond ((< n 3)
+                            (cond ((funcall comparefn x (car y))
+                                   (cond
+                                    ((not (equal x (car y)))
+                                     (rplacd y (cons (car y) (cdr y)))
+                                     (rplaca y x))))
+                                  ((eq n 1) (rplacd y (cons x (cdr y))))
+                                  ((funcall comparefn x (cadr y))
+                                   (cond
+                                    ((not (equal x (cadr y)))
+                                     (rplacd (cdr y)
+                                             (cons (cadr y) (cddr y)))
+                                     (rplaca (cdr y) x))))
+                                  (t (rplacd (cdr y) (cons x (cddr y))))))
+                           ((funcall comparefn x (car y))
+                            (cond
+                             ((not (equal x (car y)))
+                              (setq n (sub1 n1))
+                              (go a))))
+                           (t (setq l1 (cdr y)) (setq n (- n n1)) (go a))))
+               l)))
+
+
+
+
+(def kwote (lambda (x) (list 'quote x)))
+
+(def lconc
+     (lambda 
+      (ptr x)
+      (prog (xx)
+            (return
+             (cond ((atom x) ptr)
+                   (t (setq xx (last x))
+                      (cond ((atom ptr) (cons x xx))
+                            ((dtpr (cdr ptr))
+                             (rplacd (cdr ptr) x)
+                             (rplacd ptr xx))
+                            (t (rplaca (rplacd ptr xx) x)))))))))
+(def ldiff
+     (lambda (x y)
+      (cond ((eq x y) nil)
+            ((null y) x)
+            (t
+             (prog (v z)
+                   (setq z (setq v (ncons (car x))))
+              loop (setq x (cdr x))
+                   (cond ((eq x y) (return z))
+                         ((null x) (error "not a tail - ldiff")))
+                   (setq v (cdr (rplacd v (ncons (car x)))))
+                   (go loop))))))
+
+(def lsubst
+     (lambda (x y z)
+      (cond ((null z) nil)
+            ((atom z) (cond ((eq y z) x) (t z)))
+            ((equal y (car z)) (nconc (copy x) (lsubst x y (cdr z))))
+            (t (cons (lsubst x y (car z)) (lsubst x y (cdr z)))))))
+
+(def merge
+   (lambda (a b %%cfn)
+      (declare (special %%cfn))
+      (cond ((null %%cfn) (setq %%cfn (function alphalessp))))
+      (merge1 a b)))
+
+(def merge1
+   (lambda (a b)
+      (declare (special %%cfn))
+      (cond ((null a) b)
+           ((null b) a)
+           (t
+              (prog (val end)
+                 (setq val
+                       (setq end
+                             (cond ((funcall %%cfn (car a) (car b))
+                                    (prog1 a (setq a (cdr a))))
+                                   (t (prog1 b (setq b (cdr b)))))))
+                 loop (cond ((null a) (rplacd end b) (return val))
+                            ((null b) (rplacd end a) (return val))
+                            ((funcall %%cfn (car a) (car b))
+                             (rplacd end a)
+                             (setq a (cdr a)))
+                            (t (rplacd end b) (setq b (cdr b))))
+                 (setq end (cdr end))
+                 (go loop))))))
+
+(defmacro neq (a b) `(not (eq ,a ,b)))
+
+(putd 'nthchar (getd 'getchar))
+;(def nthchar
+;     (lambda (x n)
+;      (cond ((plusp n) (car (Cnth (explodec x) n)))
+;            ((minusp n) (car (Cnth (reverse (explodec x)) (minus n))))
+;            ((zerop n) nil))))
+
+(defmacro quote! (&rest a) (quote!-expr-mac a))
+
+(eval-when (compile eval load)
+   
+(defun quote!-expr-mac (form)
+   (cond ((null form) nil)
+        ((atom form) `',form)
+        ((eq (car form) '!)
+         `(cons ,(cadr form) ,(quote!-expr-mac (cddr form))))
+        ((eq (car form) '!!)
+         (cond ((cddr form) `(append ,(cadr form)
+                                      ,(quote!-expr-mac (cddr form))))
+               (t (cadr form))))
+        (t `(cons ,(quote!-expr-mac (car form))
+                   ,(quote!-expr-mac (cdr form))))))
+
+)
+
+(defun remove (item list &optional (cnt -1))
+  (let ((head '())
+       (tail nil))
+    (do ((l list (cdr l))
+        (newcell))
+       ((null l) head)
+      (cond ((or (not (equal (car l) item))
+                (zerop cnt))
+            (setq newcell (list (car l)))
+            (cond ((null head) (setq head newcell))
+                  (t (rplacd tail newcell)))
+            (setq tail newcell))
+           (t (setq cnt (1- cnt)))))))
+
+(def subpair
+     (lambda (old new expr)
+      (cond (old (subpr expr old (or new '(nil)))) (t expr))))
+
+(def subpr
+   (lambda (expr l1 l2)
+          (prog (d a)
+                (cond ((atom expr) (go lp))
+                      ((setq d (cdr expr)) (setq d (subpr d l1 l2))))
+                (setq a (subpr (car expr) l1 l2))
+                (return
+                   (cond ((or (neq a (car expr))
+                              (neq d (cdr expr))) (cons a d))
+                         (t expr)))
+                lp   (cond ((null l1) (return expr))
+                           (l2 (cond ((eq expr (car l1))
+                                      (return (car l2)))))
+                           (t (cond ((eq expr (caar l1))
+                                     (return (cdar l1))))))
+                (setq l1 (cdr l1))
+                (and l2 (setq l2 (or (cdr l2) '(nil))))
+                (go lp))))
+(def tailp
+   (lambda (x y)
+          (and x
+               (prog nil
+                     lp   (cond ((atom y) (return nil)) ((eq x y) (return x)))
+                 (setq y (cdr y))
+                 (go lp)))))
+
+(def tconc
+     (lambda (p x)
+      (cond ((atom p) (cons (setq x (ncons x)) x))
+            ((dtpr (cdr p)) (rplacd p (cdr (rplacd (cdr p) (ncons x)))))
+            (t (rplaca p (cdr (rplacd p (ncons x))))))))
+
+;--- int:vector-range-error
+; this is called from compiled code if a vector reference is made
+; which is out of bounds.  it should print an error message and
+; never return
+(defun int:vector-range-error (vec index)
+   (error "vector index out of range detected in compiled code "
+         (list vec index)))
+
+;--- int:wrong-number-of-args-error :: pass wna error message to user
+; this is called from compiled code (through wnaerr in the C interpreter)
+; when it has been detected that the wrong number of arguments have
+; been passed.  The state of the arguments are:
+;      args 1 to (- n 3) are the acutal arguments
+;      arg (- n 2) is the name of the function called
+;      arg (- n 1) is the minimum number of arguments allowed
+;      arg n is the maximum number of arguments allowed
+;              (or -1 if there is no maximum)
+(defun int:wrong-number-of-args-error n
+   (let ((max (arg n))
+        (min (arg (1- n)))
+        (name (arg (- n 2))))
+      (do ((i (- n 3) (1- i))
+          (x)
+          (args))
+         ((<& i 1)
+          ; cases
+          ;  exact number
+          ;  min and max
+          ;  only a min
+          (if (=& min max)
+             then (setq x
+                   (format nil
+                    "`~a' expects ~r argument~p but was given ~@d:"
+                    name min min (length args)))
+           elseif (=& max -1)
+             then (setq x
+                   (format nil
+                    "`~a' expects at least ~r argument~p but was given ~@d:"
+                     name min min (length args)))
+             else (setq x
+                   (format nil
+                    "`~a' expects between ~r and ~r arguments but was given ~@d:"
+                    name min max (length args))))
+                  
+          (error x args))
+         (push (arg i) args))))   
+;--- functions to retrieve parts of the vector returned by
+;    filestat
+;
+(eval-when (compile eval)
+   (defmacro filestat-chk (name index)
+            `(defun ,name (arg)
+                     (cond ((vectorp arg)
+                            (vref arg ,index))
+                           (t (error (concat ',name '|: bad arg |) arg))))))
+(filestat-chk filestat:mode    0)
+(filestat-chk filestat:type    1)
+(filestat-chk filestat:nlink   2)
+(filestat-chk filestat:uid     3)
+(filestat-chk filestat:gid     4)
+(filestat-chk filestat:size    5)
+(filestat-chk filestat:atime   6)
+(filestat-chk filestat:mtime   7)
+(filestat-chk filestat:ctime   8)
+(filestat-chk filestat:dev     9)
+(filestat-chk filestat:rdev    10)
+(filestat-chk filestat:ino     11)
+
+;; lisp coded showstack and baktrace.
+;;
+
+(declare (special showstack-prinlevel showstack-prinlength
+                 showstack-printer prinlevel prinlength))
+
+(or (boundp 'showstack-prinlevel) (setq showstack-prinlevel 3))
+(or (boundp 'showstack-prinlength) (setq showstack-prinlength 4))
+(or (boundp 'showstack-printer)        (setq showstack-printer 'print))
+(or (getd 'old-showstack) (putd 'old-showstack (getd  'showstack)))
+(or (getd 'old-baktrace) (putd 'old-baktrace (getd  'baktrace)))
+
+;--- showstack :: do a stack backtrace.
+; arguments (unevaluated) are
+;      t  - print trace expressions too (normally they are not printed)
+;      N  - for some fixnum N, only print N levels.
+;      len N - set prinlength to N
+;      lev N - set prinlevel to N
+;
+(defun showstack fexpr (args)
+   (showstack-baktrace args t))
+
+(defun baktrace fexpr (args)
+   (showstack-baktrace args nil))
+
+(defun showstack-baktrace (args showstackp)
+   (let ((print-trace nil)
+        (levels-to-print -1)
+        (prinlevel showstack-prinlevel)
+        (prinlength showstack-prinlength)
+        (res nil)
+        (newres nil)
+        (oldval nil)
+        (stk nil))
+      ;; scan arguments
+      (do ((xx args (cdr xx)))
+         ((null xx))
+         (cond ((eq t (car xx)) (setq print-trace t))
+               ((fixp (car xx)) (setq levels-to-print (car xx)))
+               ((eq 'lev (car xx))
+                (setq xx (cdr xx) prinlevel (car xx)))
+               ((eq 'len (car xx))
+                (setq xx (cdr xx) prinlength (car xx)))))
+      ;; print the levels
+      (do ((levs levels-to-print)
+          (firsttime t nil))
+         ((or (equal 0 stk)
+              (zerop levs))
+          (terpr))
+         (setq res (int:showstack stk))
+         (cond ((null res) (terpr) (return nil)))
+         (setq stk (cdr res)
+               res (car res))
+         (cond ((or print-trace (not (trace-funp res)))
+                (cond ((and oldval showstackp)
+                       (setq newres (subst-eq '<**> oldval res)))
+                      (t (setq newres res)))
+                (cond (showstackp (funcall showstack-printer newres) (terpr))
+                      (t (baktraceprint newres firsttime)))
+                (setq levs (1- levs))
+                (setq oldval res))))))
+
+(defun baktraceprint (form firsttime)
+   (cond ((not firsttime) (patom " -- ")))
+   (cond ((> (nwritn) 65) (terpr)))
+   (cond ((atom form) (print form))
+        (t (let ((prinlevel 1)
+                 (prinlength 2))
+              (cond ((dtpr form) (print (car form)))
+                    (t (print form)))))))
+
+
+;--- trace-funp  :: see if this is a trace function call
+; return t if this call is a result of tracing a function, or of calling
+; showstack
+;
+(defun trace-funp (expr)
+   (or (and (symbolp expr)
+           (memq expr '(T-eval  T-apply T-setq
+                                eval int:showstack showstack-baktrace)))
+       (and (dtpr expr)
+           (cond ((symbolp (car expr))
+                  (memq (car expr) '(trace-break T-cond T-eval T-setq
+                                                 T-apply)))
+                 ((dtpr (car expr))
+                  (and (eq 'lambda (caar expr))
+                       (eq 'T-arglst (caadar expr))))))))
+
+;--- subst-eq  :: replace parts eq to new with old
+; make new list structure
+;
+(defun subst-eq (new old list)
+   (cond ((eq old list)
+         new)
+        ((and (dtpr list)
+              (subst-eqp old list))
+         (cond ((eq old (car list))
+                (cons new (subst-eq new old (cdr list))))
+               ((dtpr (car list))
+                (cons (subst-eq new old (car list))
+                      (subst-eq new old (cdr list))))
+               (t (cons (car list)
+                        (subst-eq new old (cdr list))))))
+        (t list)))
+
+(defun subst-eqp (old list)
+   (cond ((eq old list) t)
+        ((dtpr list)
+         (or (subst-eqp old (car list))
+             (subst-eqp old (cdr list))))
+        (t nil)))
+
+
+
+;;; environment macros
+
+(defmacro environment (&rest args)
+   (do ((xx args (cddr xx))
+       (when)(action)(res))
+       ((null xx)
+       `(progn 'compile
+               ,@(nreverse res)))
+       (setq when (car xx)
+            action (cadr xx))
+       (if (atom when)
+         then (setq when (ncons when)))
+       (if (and (dtpr action)
+               (symbolp (car action)))
+         then (setq action (cons (concat "environment-" (car action))
+                                 (cdr action))))
+       (push `(eval-when ,when ,action) res)))
+       
+
+(defun environment-files fexpr (names)
+   (mapc '(lambda (filename)
+            (if (not (get filename 'version)) then (load filename)))
+        names))
+
+(defun environment-syntax fexpr (names)
+   (mapc '(lambda (class)
+            (caseq class
+                (maclisp (cvttomaclisp))
+                (intlisp (cvttointlisp))
+                (ucilisp (cvttoucilisp))
+                ((franz franzlisp) (cvttofranzlisp))
+                (t (error "unknown syntax conversion type " class))))
+        names))
+
+;--- standard environments
+(defmacro environment-maclisp (&rest args)
+   `(environment (compile load eval) (files machacks)
+                (compile eval) (syntax maclisp)
+                ,@args))
+
+
+(defmacro environment-lmlisp (&rest args)
+   `(environment (compile load eval) (files machacks lmhacks)
+                (compile eval) (syntax maclisp)
+                ,@args))
+
+;;;--- i/o functions redefined.
+; The common I/O functions are redefined here to do tilde expansion
+; if the tilde-expansion symbol is non nil
+(declare (special tilde-expansion))
+   
+;First, define the current <name> as int:<name>
+;
+(cond ((null (getd 'int:infile))
+       (putd 'int:infile (getd 'infile))
+       (putd 'int:outfile (getd 'outfile))
+       (putd 'int:fileopen (getd 'fileopen))
+       (putd 'int:cfasl (getd 'cfasl))
+       (putd 'int:fasl (getd 'fasl))))
+
+;Second, define the new functions:
+
+(defun infile (filename)
+   (cond ((not (or (symbolp filename) (stringp filename)))
+         (error "infile: non symbol or string filename " filename)))
+   (cond (tilde-expansion (setq filename (tilde-expand filename))))
+   (int:infile filename))
+
+(defun outfile (filename &optional args)
+   (cond ((not (or (symbolp filename) (stringp filename)))
+         (error "outfile: non symbol or string filename " filename)))
+   (cond (tilde-expansion (setq filename (tilde-expand filename))))
+   (int:outfile filename args))
+
+;--- fileopen :: open a file with a non-standard stdio file
+;  [this should probably be flushed because it depends on stdio,
+;   which we may not use in the future]
+(defun fileopen (filename mode)
+   (cond ((not (or (symbolp filename) (stringp filename)))
+         (error "fileopen: non symbol or string filename " filename)))
+   (cond (tilde-expansion (setq filename (tilde-expand filename))))
+   (int:fileopen filename mode))
+
+(defun fasl (filename &rest args)
+   (cond ((not (or (symbolp filename) (stringp filename)))
+         (error "fasl: non symbol or string filename " filename)))
+   (cond (tilde-expansion (setq filename (tilde-expand filename))))
+   (lexpr-funcall 'int:fasl filename args))
+
+(defun cfasl (filename &rest args)
+   (cond ((not (or (symbolp filename) (stringp filename)))
+         (error "cfasl: non symbol or string filename " filename)))
+   (cond (tilde-expansion (setq filename (tilde-expand filename))))
+   (lexpr-funcall 'int:cfasl filename args))
+
+
+;--- probef :: test if a file exists
+;
+(defun probef (filename)
+   (cond ((not (or (symbolp filename) (stringp filename)))
+         (error "probef: non symbol or string filename " filename)))
+   (sys:access filename 0))
+
+
+
+(declare (special user-name-to-dir-cache))
+(or (boundp 'user-name-to-dir-cache) (setq user-name-to-dir-cache nil))
+
+;--- username-to-dir
+; given a user name, return the home directory name
+;
+(defun username-to-dir (name)
+   (cond ((symbolp name) (setq name (get_pname name)))
+        ((stringp name))
+        (t (error "username-to-dir: Illegal name " name)))
+   (let ((val (assoc name user-name-to-dir-cache)))
+      (cond ((null val)
+            (setq val (sys:getpwnam name))
+            (cond (val (push (cons name val) user-name-to-dir-cache))))
+           (t (setq val (cdr val))))
+      (cond (val (sys:getpwnam-dir val)))))
+                   
+;--- username-to-dir-flush-cache :: clear all memory of where users are
+; it is important to call this function upon startup to clear all
+; knowledge of pathnames since this object file could have been copied
+; from another machine
+;
+(defun username-to-dir-flush-cache ()
+   (setq user-name-to-dir-cache nil))
+
+;--- lisp interface to int:franz-call
+;
+(eval-when (compile eval)
+   (setq fc_getpwnam 1   fc_access 2  fc_chdir 3  fc_unlink 4
+        fc_time   5     fc_chmod  6  fc_getpid 7 fc_stat  8
+        fc_gethostname 9 fc_link 10))
+
+;--- sys:getpwnam
+; (sys:getpwnam 'st_username)
+; rets vector: (t_name x_uid x_gid t_dir)
+;
+(defun sys:getpwnam (name)
+   (cond ((or (symbolp name) (stringp name))
+         (int:franz-call #.fc_getpwnam name))
+        (t (error "sys:getpwnam : illegal name " name))))
+
+; return dir portion
+;
+(defun sys:getpwnam-dir (vec) (vref vec 3))
+
+(defun sys:access (name class)
+   (cond ((and (or (symbolp name) (stringp name))
+              (fixp class))
+         (cond (tilde-expansion (setq name (tilde-expand name))))
+         (zerop (int:franz-call #.fc_access name class)))
+        (t (error "sys:access : illegal name or class " name class))))
+
+(defun chdir (dir)
+   (cond ((or (symbolp dir) (stringp dir))
+         (cond (tilde-expansion (setq dir (tilde-expand dir))))
+         (cond ((zerop (int:franz-call #.fc_chdir dir)))
+               (t (error "cd: can't chdir to " dir))))
+        (t (error "chdir: illegal argument " dir))))
+
+;--- sys:unlink :: unlink (remove) a file
+;
+(defun sys:unlink (name)
+   (cond ((or (symbolp name) (stringp name))
+         (cond (tilde-expansion (setq name (tilde-expand name))))
+         (cond ((zerop (int:franz-call #.fc_unlink name)))
+               (t (error "sys:unlink : unlink failed of " name))))
+        (t (error "sys:unlink : illegal argument " name))))
+
+;--- sys:link :: make (hard) link to file
+;
+(defun sys:link (oldname newname)
+   (cond ((or (symbolp oldname) (stringp oldname))
+         (cond (tilde-expansion (setq oldname (tilde-expand oldname))))
+         (cond ((or (symbolp newname) (stringp newname))
+                (cond (tilde-expansion (setq newname 
+                                               (tilde-expand newname))))
+                (cond ((zerop (int:franz-call #.fc_link oldname newname)))
+                      (t (error "sys:link : unlink failed of "
+                                oldname newname))))
+               (t (error "sys:unlink : illegal argument " newname))))
+        (t (error "sys:unlink : illegal argument " oldname))))
+
+;--- sys:time :: return 'absolute' time in seconds
+;
+(defun sys:time ()
+   (int:franz-call #.fc_time))
+
+;--- sys:chmod :: change mode of file
+; return t iff it succeeded.
+;
+(defun sys:chmod (name mode)
+   (cond ((and (or (stringp name) (symbolp name))
+              (fixp mode))
+         (cond (tilde-expansion (setq name (tilde-expand name))))
+         (cond ((zerop (int:franz-call #.fc_chmod name mode)))
+               (t (error "sys:chmod : chmod failed of " name))))
+        (t (error "sys:chmod : illegal argument(s): " name mode))))
+   
+(defun sys:getpid ()
+   (int:franz-call #.fc_getpid))
+
+(defun filestat (name)
+   (let (ret)
+      (cond ((or (symbolp name) (stringp name))
+            (cond (tilde-expansion (setq name (tilde-expand name))))
+            (cond ((null (setq ret (int:franz-call #.fc_stat name)))
+                   (error "filestat : file doesn't exist " name))
+                  (t ret)))
+           (t (error "filestat : illegal argument " name)))))
+
+;--- sys:gethostname :: retrieve the current host name as a string
+;
+(defun sys:gethostname ()
+   (int:franz-call #.fc_gethostname))
+
diff --git a/usr/src/ucb/lisp/lisplib/common3.l b/usr/src/ucb/lisp/lisplib/common3.l
new file mode 100644 (file)
index 0000000..5158ec0
--- /dev/null
@@ -0,0 +1,98 @@
+(setq rcs-common2-
+   "$Header: common3.l,v 1.3 83/09/11 09:44:14 jkf Exp $")
+
+;;
+;; common3.l                           -[Sat Sep 10 10:51:18 1983 by jkf]-
+;;
+;;
+
+(declare (macros t))
+
+(defun litatom macro (x)
+  `(and (atom . ,(cdr x))
+       (not (numberp . ,(cdr x)))))
+
+; This function really should compile optimally in-line
+;
+(defun nequal (arg1 arg2)
+  (not (equal arg1 arg2)))
+
+(defun lineread (&rest args)
+   (let (flag port)
+      (mapc (function          ; get the options
+              (lambda (x)
+                 (cond ((portp x) (setq port x))
+                       ((setq flag x)))))
+           args)
+      (cond ((not (and flag    ; flag for empty line
+                      (eq (tyipeek port) #\lf)
+                      (tyi port)))
+            (prog (input)
+               (setq input (ncons nil))  ; initialize for tconc.
+               (tconc input (read port))       ; do read to make sure
+                                               ; an s-expression gets read
+               loop
+               (cond ((not (eq (tyipeek port) #\lf))
+                      (tconc input (read port))
+                      (go loop))
+                     ( t ; the actual list is in the CAR.
+                       (tyi port)
+                       (return (car input)))))))))
+
+(defun defv fexpr (l)
+  (set (car l) (cadr l)))
+
+
+(defun initsym (&rest l)
+   (mapcar (function initsym1) l))
+
+(defun initsym1 expr (l)
+   (prog (num)
+      (cond ((dtpr l)
+            (setq num (cadr l))
+            (setq l (car l)))
+           ( t (setq num 0)))
+      (putprop l num 'symctr)
+      (return (concat l num))))
+
+(defun newsym (name)
+   (concat name
+          (putprop name
+                   (1+ (or (get name 'symctr)
+                           -1))
+                   'symctr)))
+
+(defun oldsym (sym)
+   (cond ((get sym 'symctr) (concat sym (get sym 'symctr)))
+        ( t sym)))
+
+(defun allsym (name)
+   (prog (num symctr syms)
+      (cond ((dtpr name)
+            (setq num (cadr name))
+            (setq name (car name)))
+           ( t (setq num 0)))
+      (or (setq symctr (get name 'symctr))
+         (return))
+      loop
+      (and (>& num symctr)
+          (return syms))
+      (setq syms (cons (concat name symctr) syms))
+      (setq symctr (1- symctr))
+      (go loop)))
+
+(defun remsym (&rest l)
+   (mapcar (function remsym1) l))
+
+(defun remsym1 expr (l)
+   (prog1 (oldsym (cond ((dtpr l) (car l))
+                       ( t l)))
+         (mapc (function remob) (allsym l))
+         (cond ((dtpr l)
+                (putprop (car l) (1- (cadr l)) 'symctr))
+               ( t (remprop l 'symctr)))))
+
+(defun symstat (&rest l)
+   (mapcar (function (lambda (k)
+                       (list k (get k 'symctr))))
+          l))
diff --git a/usr/src/ucb/lisp/lisplib/fix.l b/usr/src/ucb/lisp/lisplib/fix.l
new file mode 100644 (file)
index 0000000..9eaa0d9
--- /dev/null
@@ -0,0 +1,687 @@
+(setq rcs-fix-
+   "$Header: /usr/lib/lisp/RCS/fix.l,v 1.2 83/08/06 08:39:58 jkf Exp $")
+
+; vi: set lisp :
+
+(eval-when (compile eval)
+  (or (get 'cmumacs 'version) (load 'cmumacs)))
+
+; LWE 1/11/81 Hack hack....
+;
+; LWE 1/11/81 Bet you didn't know this, but this won't work INTERPRETED,
+;            but Dave assures me it works compiled. (In MACLisp...)
+; 
+(declare (special cmd frame x cnt var init label part incr limit selectq))
+
+(dv fixfns
+    ((*** This is FIXIT written by David Touretzky and adapted to Franz by Don
+      Cohen)
+     (declare (special framelist rframelist interrupt-handlers handler-labels)
+              (special prinlevel prinlength evalhook-switch traced-stuff)
+              (special lastword piport hush-debug)
+              (*fexpr editf step type))
+     (sstatus feature fixit)
+     (*rset t)
+     ER%tpl
+     fixit
+     debug
+     debug-iter
+     debug1
+     debug-bktrace
+     debug-print
+     debug-print1
+     debug-findcall
+     debug-replace-function-name
+     debug-scanflist
+     debug-scanstk
+     debug-getframes
+     debug-nextframe
+     debug-upframe
+     debug-dnframe
+     debug-upfn
+     debug-dnfn
+     debug-showvar
+     debug-nedit
+     debug-insidep
+     debug-findusrfn
+     debug-findexpr
+     debug-pop
+     debug-where
+     debug-sysp
+     interrupt-handlers
+     handler-labels
+     (or (boundp 'traced-stuff) (setq traced-stuff nil))
+     (or (boundp 'evalhook-switch) (setq evalhook-switch nil))
+     (setq hush-debug nil)))
+
+(or (boundp 'traced-stuff) (setq traced-stuff nil))
+(or (boundp 'evalhook-switch) (setq evalhook-switch nil))
+(or (boundp 'debug-sysmode) (setq debug-sysmode nil))
+(setq hush-debug nil)
+
+(*** This is FIXIT written by David Touretzky and adapted to Franz by Don Cohen)
+
+(declare (special framelist rframelist interrupt-handlers handler-labels)
+         (special prinlevel prinlength evalhook-switch traced-stuff)
+         (special lastword piport hush-debug debug-sysmode)
+         (*fexpr editf step type))
+
+(defvar fixit-eval nil)
+(defvar fixit-print nil)
+(defvar fixit-pp nil)
+
+(sstatus feature fixit)
+
+(*rset t)
+
+; (jkf) it is not clear that you want this to take over on all errors,
+; but the cmu people seem to want that.
+#+cmu (progn 'compile
+            (dv ER%tpl fixit)
+            (dv ER%all fixit) ; LWE 1/17/81 MAYBE THIS WILL FIX THIS code
+            )
+
+;--- eval, print and pretty-print functions are user-selectable by just
+; assigning another value to fixit-eval, fixit-print and fixit-pp.
+;
+(defmacro fix-eval (&rest args)
+   `(cond ((and fixit-eval
+               (getd fixit-eval))
+          (funcall fixit-eval ,@args))
+         (t (eval ,@args))))
+
+(defmacro fix-print (&rest args)
+   `(cond ((and fixit-print
+               (getd fixit-print))
+          (funcall fixit-print ,@args))
+         (t (print ,@args))))
+
+(defmacro fix-pp (&rest args)
+   `(cond ((and fixit-pp
+               (getd fixit-pp))
+          (funcall fixit-pp ,@args))
+         (t ($prpr ,@args))))
+
+(def fixit
+  (nlambda (l)
+    (prog (piport)
+          (do nil (nil) (eval (cons 'debug l))))))
+
+(def debug
+  (nlambda (params)
+    (prog (cmd frame framelist rframelist nframe val infile)
+          (setq infile t)
+          (and evalhook-switch (step nil))
+          (setq rframelist
+                (reverse
+                 (setq framelist
+                       (or (debug-getframes)
+                           (list
+                            (debug-scanstk '(nil) '(debug)))))))
+          (setq frame (debug-findexpr (car framelist)))
+          ;(tab 0)
+          (cond
+           ((and (car params) (not (eq (car params) 'edit)))
+            (terpri)
+            (princ '|;debug: |)
+            (princ (cadddr params))
+            (cond ((cddddr params)
+                   (princ '| -- |)
+                   (fix-print (cddddr params))))
+            (terpri)
+            (go loop)))
+          (debug-print1 frame nil)
+          (terpri)
+          (cond (hush-debug (setq hush-debug nil) (go loop))
+                ((not (memq 'edit params)) (go loop)))
+          (drain nil)
+          (princ '|type e to edit, <cr> to debug: |)
+          (setq val (tyi))
+          (cond ((or (= val 69) (= val 101))
+                 (and (errset (debug-nedit frame))
+                      (setq cmd '(ok))
+                      (go cmdr)))
+                ((or (= val 78) (= val 110)) (terpri) (debug-pop)))
+     loop (terpri)
+          (princ ':)
+          (cond ((null (setq cmd (lineread))) (reset)))
+     cmdr (cond
+           ((dtpr (car cmd))
+            (setq val (fix-eval (car cmd) (cadddr frame)))
+            (fix-print val)
+            (terpri)
+            (go loop)))
+          (setq nframe (debug1 cmd frame))
+          (and (not (atom nframe)) (setq frame nframe) (go loop))
+          (fix-print (or nframe (car cmd)))
+          (princ '" Huh? - type h for help")
+          (go loop))))
+
+(def debug-iter
+  (macro (x)
+    (cons 'prog
+          (cons 'nil
+                (cons 'loop
+                      (cons (list 'setq 'nframe (cadr x))
+                            '((setq cnt (|1-| cnt))
+                              (and (or (null nframe) (zerop cnt))
+                                   (return nframe))
+                              (setq frame nframe)
+                              (go loop))))))))
+
+(def debug1
+  (lambda (cmd frame)
+    (prog (nframe val topframe cnt item)
+          (setq topframe (car framelist))
+          (or (eq (typep (car cmd)) 'symbol) (return nil))
+          ; if "> name", replace function or variable name with new atom
+          (and (eq (car cmd) '>)
+               (return (debug-replace-function-name cmd topframe)))
+          (and (eq (getchar (car cmd) 1) 'b)
+               (eq (getchar (car cmd) 2) 'k)
+               (return (debug-bktrace cmd frame)))
+          (setq cnt
+                (cond ((fixp (cadr cmd)) (cadr cmd))
+                      ((fixp (caddr cmd)) (caddr cmd))
+                      (t 1)))
+          (and (< cnt 1) (setq cnt 1))
+          (setq item
+                (cond ((symbolp (cadr cmd)) (cadr cmd))
+                      ((symbolp (caddr cmd)) (caddr cmd))))
+          (and item
+               (cond ((memq (car cmd) '(u up))
+                      (setq cmd (cons 'ups (cdr cmd))))
+                     ((memq (car cmd) '(d dn))
+                      (setq cmd (cons 'dns (cdr cmd))))))
+          (selectq (car cmd)
+                   (top (debug-print1 (setq frame topframe) nil))
+                   (bot (debug-print1 (setq frame (car rframelist)) nil))
+                   (p (debug-print1 frame nil))
+                   (pp (fix-pp (caddr frame)))
+                   (where (debug-where frame))
+                   (help
+                    (cond ((cdr cmd) (eval cmd))
+                          (t (ty |/usr/lib/lisp/fixit.ref|))))
+                   ((? h) (ty |/usr/lib/lisp/fixit.ref|))
+                   ((go ok)
+                    (setq frame (debug-findexpr topframe))
+                    (cond ((eq (caaddr frame) 'debug)
+                           (freturn (cadr frame) t))
+                          (t (fretry (cadr frame) frame))))
+                   (pop (debug-pop))
+                   (step (setq frame (debug-findexpr frame))
+                         (step t)
+                         (fretry (cadr (debug-dnframe frame)) frame))
+                   (redo (and item
+                              (setq frame
+                                    (debug-findcall item frame framelist)))
+                         (and frame (fretry (cadr frame) frame)))
+                   (return (setq val (eval (cadr cmd)))
+                           (freturn (cadr frame) val))
+                   (edit (debug-nedit frame))
+                   (editf
+                    (cond ((null item)
+                           (setq frame
+                                 (or (debug-findusrfn (debug-nedit frame))
+                                     (car rframelist))))
+                          ((dtpr (getd item))
+                           (errset (funcall 'editf (list item))))
+                          (t (setq frame nil))))
+                   (u (debug-iter (debug-upframe frame))
+                      (cond
+                       ((null nframe) (terpri) (princ '|<top of stack>|)))
+                      (debug-print1 (setq frame (or nframe frame)) nil))
+                   (d (setq nframe
+                            (or (debug-iter (debug-dnframe frame)) frame))
+                      (debug-print1 nframe nil)
+                      (cond ((eq frame nframe)
+                             (terpri)
+                             (princ '|<bottom of stack>|))
+                            (t (setq frame nframe))))
+                   (up (setq nframe (debug-iter (debug-upfn frame)))
+                       (cond
+                        ((null nframe) (terpri) (princ '|top of stack|)))
+                       (setq frame (or nframe topframe))
+                       (debug-print1 frame nil))
+                   (dn (setq frame
+                             (or (debug-iter (debug-dnfn frame))
+                                 (car rframelist)))
+                       (debug-print1 frame nil)
+                       (cond
+                        ((not (eq frame nframe))
+                         (terpri)
+                         (princ '|<bottom of stack>|))))
+                   (ups (setq frame
+                              (debug-iter
+                               (debug-findcall item frame rframelist)))
+                        (and frame (debug-print1 frame nil)))
+                   (dns (setq frame
+                              (debug-iter
+                               (debug-findcall item frame framelist)))
+                        (and frame (debug-print1 frame nil)))
+                  (sys (setq debug-sysmode (not debug-sysmode))
+                       (patom "sysmode now ")(patom debug-sysmode) (terpr))
+                   (cond ((not (dtpr (car cmd)))
+                          (*** should there also be a boundp test here)
+                          (debug-showvar (car cmd) frame))
+                         (t (setq frame (car cmd)))))
+          (return (or frame item)))))
+
+(def debug-replace-function-name 
+  (lambda (cmd frame)
+    (prog (oldname newname errorcall nframe)
+         (setq errorcall (caddr frame))
+         (cond ((eq (caddddr errorcall) '|eval: Undefined function |)
+                (setq oldname (cadddddr errorcall))
+                (setq newname (cadr cmd))
+                (setq cnt 3.)
+                (setq frame (debug-iter (debug-dnframe frame)))
+                (dsubst newname oldname frame)
+                (fretry (cadr frame) frame))
+               ((eq (caddddr errorcall) '|Unbound Variable:|)
+                (setq oldname (cadddddr errorcall))
+                (setq newname (eval (cadr cmd)))
+                (setq cnt 3.)
+                (setq frame (debug-iter (debug-dnframe frame)))
+                (dsubst newname oldname frame)
+                (fretry (cadr frame) frame))
+               ( t (return nil))))))
+
+(def debug-bktrace
+  (lambda (cmd oframe)
+    (prog (sel cnt item frame nframe)
+          (mapc '(lambda (x)
+                         (setq sel
+                               (cons (selectq x
+                                              (f 'fns)
+                                              (a 'sysp)
+                                              (v 'bind)
+                                              (e 'expr)
+                                              (c 'current)
+                                              'bogus)
+                                     sel)))
+                (cddr (explodec (car cmd))))
+          (setq item
+                (cond ((eq (typep (cadr cmd)) 'symbol) (cadr cmd))
+                      ((eq (typep (caddr cmd)) 'symbol) (caddr cmd))))
+          (cond ((debug-sysp item) (setq sel (cons 'sysp sel)))
+                ((not (memq 'sysp sel))
+                 (setq sel (cons 'user sel))))
+          (setq cnt
+                (cond ((fixp (cadr cmd)) (cadr cmd))
+                      ((fixp (caddr cmd)) (caddr cmd))
+                      (item 1)))
+          (cond ((null cnt)
+                 (setq frame
+                       (cond ((memq 'current sel) oframe)
+                             (t (car rframelist))))
+                 (go dbpr))
+                ((null item)
+                 (setq frame (car framelist))
+                 (and (or (not (memq 'user sel))
+                          (atom (caddr (car framelist)))
+                          (not (debug-sysp (caaddr (car framelist)))))
+                      (setq cnt (|1-| cnt)))
+                 (setq frame
+                       (cond ((zerop cnt) frame)
+                             ((memq 'user sel)
+                              (debug-iter (debug-dnfn frame)))
+                             (t (debug-iter (debug-dnframe frame)))))
+                 (setq frame (or frame (car rframelist)))
+                 (go dbpr))
+                (t (setq frame (car framelist))))
+          (setq frame
+                (cond ((and (= cnt 1)
+                            (not (atom (caddr (car framelist))))
+                            (eq item (caaddr (car framelist))))
+                       (car framelist))
+                      ((debug-iter (debug-findcall item frame framelist)))
+                      (t (car rframelist))))
+     dbpr (debug-print frame sel oframe)
+          (cond ((eq frame (car rframelist))
+                 (terpri)
+                 (princ '|<bottom of stack>|)
+                 (terpri))
+                (t (terpri)))
+          (cond
+           ((memq 'bogus sel)
+            (terpri)
+            (princ (car cmd))
+            (princ '| contains an invalid bk modifier|)))
+          (return oframe))))
+
+(def debug-print
+  (lambda (frame sel ptr)
+    (prog (curframe)
+          (setq curframe (car framelist))
+     loop (cond ((not
+                  (and (memq 'user sel)
+                       (not (atom (caddr curframe)))
+                       (debug-sysp (caaddr curframe))))
+                 (debug-print1 curframe sel)
+                 (and (eq curframe ptr) (princ '|   <--- you are here|)))
+                ((eq curframe ptr)
+                 (terpri)
+                 (princ '|  <--- you are somewhere in here|)))
+          (and (eq curframe frame) (return frame))
+          (setq curframe (debug-dnframe curframe))
+          (or curframe (return frame))
+          (go loop))))
+
+(def debug-print1
+  (lambda (frame sel)
+    (prog (prinlevel prinlength varlist)
+          (and (not (memq 'expr sel))
+               (setq prinlevel 2)
+               (setq prinlength 5))
+          (cond
+           ((atom (caddr frame))
+            (terpri)
+            (princ '|   |)
+            (fix-print (caddr frame))
+            (princ '| <- eval error|)
+            (return t)))
+          (and (memq 'bind sel)
+               (cond ((memq (caaddr frame) '(prog lambda))
+                      (setq varlist (cadr (caddr frame))))
+                     ((and (atom (caaddr frame)) (dtpr (getd (caaddr frame))))
+                      (setq varlist (cadr (getd (caaddr frame))))))
+               (mapc (function
+                      (lambda (v)
+                              (debug-showvar v
+                                             (or (debug-upframe frame)
+                                                 frame))))
+                     (cond ((and varlist (atom varlist)) (ncons varlist))
+                           (t varlist))))
+          (and (memq 'user sel)
+               (debug-sysp (caaddr frame))
+               (return nil))
+          (cond ((memq (caaddr frame) interrupt-handlers)
+                 (terpri)
+                 (princ '<------------)
+                 (fix-print (cadr (assq (caaddr frame) handler-labels)))
+                 (princ '-->))
+                ((eq (caaddr frame) 'debug)
+                 (terpri)
+                 (princ '<------debug------>))
+                ((memq 'fns sel)
+                 (terpri)
+                 (and (debug-sysp (caaddr frame)) (princ '|  |))
+                 (fix-print (caaddr frame)))
+                (t (terpri)
+                   (fix-print
+                    (cond ((eq (car frame) 'eval) (caddr frame))
+                          (t (cons (caaddr frame) (cadr (caddr frame))))))))
+          (or (not (symbolp (caaddr frame)))
+              (eq (caaddr frame) (concat (caaddr frame)))
+              (princ '|  <not interned>|))
+          (return t))))
+
+(def debug-findcall
+  (lambda (fn frame flist)
+    (prog nil
+     loop (setq frame (debug-nextframe frame flist nil))
+          (or frame (return nil))
+          (cond ((atom (caddr frame))
+                 (cond ((eq (caddr frame) fn) (return frame)) (t (go loop))))
+                ((eq (caaddr frame) fn) (return frame))
+                (t (go loop))))))
+
+(def debug-scanflist
+  (lambda (frame fnset)
+    (prog nil
+     loop (or frame (return nil))
+          (and (not (atom (caddr frame)))
+               (memq (caaddr frame) fnset)
+               (return frame))
+          (setq frame (debug-dnframe frame))
+          (go loop))))
+
+(def debug-scanstk
+  (lambda (frame fnset)
+    (prog nil
+     loop (or frame (return nil))
+          (and (not (atom (caddr frame)))
+               (memq (caaddr frame) fnset)
+               (return frame))
+          (setq frame (evalframe (cadr frame)))
+          (go loop))))
+
+(def debug-getframes
+  (lambda nil
+    (prog (flist fnew)
+          (setq fnew
+                (debug-scanstk '(nil)
+                               (cons 'debug interrupt-handlers)))
+     loop (and (not debug-sysmode)
+              (not (atom (caddr fnew)))
+               (eq (caaddr fnew) 'debug)
+               (eq (car (evalframe (cadr fnew))) 'apply)
+               (memq (caaddr (evalframe (cadr fnew))) interrupt-handlers)
+               (setq fnew (evalframe (cadr fnew))))
+          (and (not debug-sysmode)
+              (null flist)
+               (eq (car fnew) 'apply)
+               (memq (caaddr fnew) interrupt-handlers)
+               (setq fnew (evalframe (cadr fnew))))
+          (and (not debug-sysmode)
+              (eq (car fnew) 'apply)
+               (eq (typep (caaddr fnew)) 'symbol)
+               (not (eq (caaddr fnew) (concat (caaddr fnew))))
+               (setq fnew (evalframe (cadr fnew)))
+               (setq fnew (evalframe (cadr fnew)))
+               (setq fnew (evalframe (cadr fnew)))
+               (setq fnew (evalframe (cadr fnew)))
+               (go loop))
+          (and (not debug-sysmode)
+              (not (atom (caddr fnew)))
+               (memq (caaddr fnew) '(evalhook* evalhook))
+               (setq fnew (evalframe (cadr fnew)))
+               (go loop))
+          (and (not debug-sysmode)
+              (eq (car fnew) 'apply)
+               (eq (caaddr fnew) 'eval)
+               (cadadr (caddr fnew))
+               (or (not (fixp (cadadr (caddr fnew))))
+                   (= (cadadr (caddr fnew)) -1))
+               (setq fnew (evalframe (cadr fnew)))
+               (go loop))
+          (and fnew
+               (setq flist (cons fnew flist))
+               (setq fnew (evalframe (cadr fnew)))
+               (go loop))
+          (return (nreverse flist)))))
+
+(def debug-nextframe
+  (lambda (frame flist sel)
+    (prog nil
+          (setq flist (cdr (memq frame flist)))
+          (and (not (memq 'user sel)) (return (car flist)))
+     loop (or flist (return nil))
+          (cond
+           ((or (atom (caddr (car flist)))
+                (not (debug-sysp (caaddr (car flist)))))
+            (return (car flist))))
+          (setq flist (cdr flist))
+          (go loop))))
+
+(def debug-upframe
+  (lambda (frame)
+    (debug-nextframe frame rframelist nil)))
+
+(def debug-dnframe
+  (lambda (frame)
+    (debug-nextframe frame framelist nil)))
+
+(def debug-upfn
+  (lambda (frame)
+    (debug-nextframe frame rframelist '(user))))
+
+(def debug-dnfn
+  (lambda (frame)
+    (debug-nextframe frame framelist '(user))))
+
+(def debug-showvar
+  (lambda (var frame)
+    (terpri)
+    (princ '|   |)
+    (princ var)
+    (princ '| = |)
+    (fix-print
+     ((lambda (val) (cond ((atom val) '?) (t (car val))))
+      (errset (fix-eval var (cadddr frame)) nil)))))
+
+(def debug-nedit
+  (lambda (frame)
+    (prog (val body elem nframe)
+          (setq elem (caddr frame))
+          (setq val frame)
+     scan (setq val (debug-findusrfn val))
+          (or val (go nofn))
+          (setq body (getd (caaddr val)))
+          (cond ((debug-insidep elem body)
+                 (princ '=)
+                 (fix-print (caaddr val))
+                 (edite body
+                        (list 'f (cons '== elem) 'tty:)
+                        (caaddr val))
+                 (return frame))
+                ((or (eq elem (caddr val)) (debug-insidep elem (caddr val)))
+                 (setq val (debug-dnframe val))
+                 (go scan)))
+     nofn (setq nframe (debug-dnframe frame))
+          (or nframe (go doit))
+          (and (debug-insidep elem (caddr nframe))
+               (setq frame nframe)
+               (go nofn))
+     doit (edite (caddr frame)
+                 (and (debug-insidep elem (caddr frame))
+                      (list 'f (cons '== elem) 'tty:))
+                 nil)
+          (return frame))))
+
+(def debug-insidep
+  (lambda (elem expr)
+    (car (errset (edite expr (list 'f (cons '== elem)) nil)))))
+
+(def debug-findusrfn
+  (lambda (frame)
+    (cond ((null frame) nil)
+          ((and (dtpr (caddr frame))
+                (symbolp (caaddr frame))
+                (dtpr (getd (caaddr frame))))
+           frame)
+          (t (debug-findusrfn (debug-dnframe frame))))))
+
+(def debug-findexpr
+  (lambda (frame)
+    (cond ((null frame) nil)
+          ((and (eq (car frame) 'eval) (not (atom (caddr frame))))
+           frame)
+          (t (debug-findexpr (debug-dnframe frame))))))
+
+(def debug-pop
+  (lambda nil
+    (prog (frame)
+         (setq frame (car framelist))
+     l    (cond ((null (setq frame (evalframe (cadr frame))))(reset)))
+         (cond ((and (dtpr (caddr frame))(eq (caaddr frame) 'debug))
+                (freturn (cadr frame) nil)))
+         (go l))))
+
+(def debug-where
+  (lambda (frame)
+    (prog (lev diff nframe)
+          (setq lev (- (length framelist) (length (memq frame rframelist))))
+          (setq diff (- (length framelist) lev 1))
+          (debug-print1 frame nil)
+          (terpri)
+          (cond ((zerop diff) (princ '|you are at top of stack.|))
+                ((zerop lev) (princ '|you are at bottom of stack.|))
+                (t (princ '|you are |)
+                   (princ diff)
+                   (cond ((= diff 1) (princ '| frame from the top.|))
+                         (t (princ '| frames from the top.|)))))
+          (terpri)
+          (and (or (atom (caddr frame)) (not (eq (car frame) 'eval)))
+               (return nil))
+          (setq lev 0)
+          (setq nframe frame)
+     lp   (and (setq nframe (debug-findcall (caaddr nframe) nframe framelist))
+               (setq lev (|1+| lev))
+               (go lp))
+          (princ '|there are |)
+          (princ lev)
+          (princ '| |)
+          (princ (caaddr frame))
+          (princ '|'s below.|)
+          (terpri))))
+
+(def debug-sysp
+  (lambda (x)
+    (and (sysp x) (symbolp x) (not (dtpr (getd x))))))
+
+(dv interrupt-handlers (fixit))
+
+(dv handler-labels
+    ((fixit error)
+     (debug-ubv-handler ubv)
+     (debug-udf-handler udf)
+     (debug-fac-handler fac)
+     (debug-ugt-handler ugt)
+     (debug-wta-handler wta)
+     (debug-wna-handler wna)
+     (debug-iol-handler iol)
+     (debug-*rset-handler rst)
+     (debug-mer-handler mer)
+     (debug-gcd-handler gcd)
+     (debug-gcl-handler gcl)
+     (debug-gco-handler gco)
+     (debug-pdl-handler pdl)))
+
+
+(or (boundp 'traced-stuff) (setq traced-stuff nil))
+
+(or (boundp 'evalhook-switch) (setq evalhook-switch nil))
+
+(setq hush-debug nil)
+
+
+;; other functions grabbed from other cmu files to make this file complete
+;; unto itself
+
+;- from sysfunc.l
+(declare (special system-functions\\a))
+(defun build-sysp nil
+  (do ((temp (oblist) (cdr temp))
+       (sysfuncs))
+      ((null temp)(setq system-functions\\a sysfuncs));atom has ^G at end
+      (cond ((getd (car temp))
+            (setq sysfuncs (cons (car temp) sysfuncs))))))
+
+(defun sysp (x) ; (cond ((memq x system-functions\\a)t))
+       (memq x '(funcallhook* funcallhook evalhook evalhook* 
+                              continue-evaluation)))
+
+(or (boundp 'system-functions\\a) (build-sysp))
+
+(defun fretry (pdlpnt frame)
+  (freturn pdlpnt
+          (cond ((eq (car frame) 'eval) (eval (caddr frame) (cadddr frame)))
+                ((eq (car frame) 'apply)
+                 (eval `(apply ',(caaddr frame) ',(cadaddr frame)) 
+                       (cadddr frame))))))
+
+
+; - from cmu.l
+
+(def %lineread
+  (lambda (chan)
+         (prog (ans)
+          loop (setq ans (cons (read chan 'EOF) ans))
+               (cond ((eq (car ans) 'EOF) (return (reverse (cdr ans)))))
+          loop2(cond ((eq 10 (tyipeek chan)) (return (reverse ans)))
+                     ((memq (tyipeek chan) '(41 93))
+                      (tyi chan)
+                      (go loop2))
+                     (t (go loop))))))
diff --git a/usr/src/ucb/lisp/lisplib/lmhacks.l b/usr/src/ucb/lisp/lisplib/lmhacks.l
new file mode 100644 (file)
index 0000000..fadcd6c
--- /dev/null
@@ -0,0 +1,371 @@
+(setq rcs-lmhacks-
+   "$Header: /usr/lib/lisp/RCS/lmhacks.l,v 1.2 83/08/15 22:32:31 jkf Exp $")
+
+;;  This file contains miscellaneous functions and macros that 
+;;  ZetaLisp users often find useful
+
+
+;;;  (c) Copyright 1982 Massachusetts Institute of Technology 
+
+;; This is a simple multiple value scheme based on the one implemented
+;; in MACLISP.  It doesn't clean up after its self properly, so if
+;; you ask for multiple values, you will get them regardless of whether
+;; they are returned.
+
+(environment-maclisp (compile eval) (files struct flavorm))
+
+(declare (macros t))
+
+(defvar si:argn () "Number of arguments returned by last values")
+(defvar si:arg2 () "Second return value")
+(defvar si:arg3 () "Third return value")
+(defvar si:arg4 () "Fourth return value")
+(defvar si:arg5 () "Fifth return value")
+(defvar si:arg6 () "Sixth return value")
+(defvar si:arg7 () "Seventh return value")
+(defvar si:arg8 () "Eigth return value")
+(defvar si:arglist () "Additional return values after the eigth")
+
+(defvar si:return-registers
+  '(si:arg2 si:arg3 si:arg4 si:arg5 si:arg6 si:arg7 si:arg8))
+
+(defmacro values (&rest values)
+  `(prog2 (setq si:argn ,(length values))
+         ,(first values)
+         ,@(do ((vals (cdr values) (cdr vals))
+                (regs si:return-registers (cdr regs))
+                (forms))
+               (nil)
+             (cond ((null vals)
+                    (return (reverse forms)))
+                   ((null regs)
+                    (return
+                     `(,@(reverse forms)
+                       (setq si:arglist (list ,@vals)))))
+                   (t (push `(setq ,(car regs) ,(car vals))
+                            forms))))))
+
+(defun values-list (list)
+  (setq si:argn (length list))
+  (do ((vals (cdr list) (cdr vals))
+       (regs si:return-registers (cdr regs)))
+      ((null regs)
+       (if (not (null vals))
+          (setq si:arglist vals))
+       (car list))
+    (set (car regs) (car vals))))
+
+(defmacro multiple-value (vars form)
+  `(progn
+     ,@(if (not (null (car vars)))
+         `((setq ,(car vars) ,form)
+           (if (< si:argn 1) (setq ,(car vars) nil)))
+         `(,form))
+     ,@(do ((vs (cdr vars) (cdr vs))
+           (regs si:return-registers (cdr regs))
+           (i 2 (1+ i))
+           (forms))
+          (nil)
+        (cond ((null vars)
+               (return (reverse forms)))
+              ((null regs)
+               (return
+                (do ((vs vs (cdr vs)))
+                    ((null vs) (nreverse forms))
+                  (and (not (null (car vs)))
+                       (push
+                        `(setq ,(car vs)
+                               (prog1
+                                (if (not (> ,i si:argn))
+                                    (car si:arglist))
+                                (setq si:arglist (cdr si:arglist))))
+                        forms)))))
+              ((not (null (car vs)))
+               (push `(setq ,(car vs) (if (not (> ,i si:argn)) ,(car regs))
+                            ,(car regs) nil)
+                     forms))))))
+
+(defmacro multiple-value-bind (vars form &rest body)
+  `(let ,vars
+       (multiple-value ,vars ,form)
+       ,@body))
+
+(defmacro multiple-value-list (form)
+  `(multiple-value-list-1 ,form))
+
+(defun multiple-value-list-1 (si:arg1)
+  (cond ((= 0 si:argn) ())
+       ((= 1 si:argn)
+        (list si:arg1))
+       ((= 2 si:argn)
+        (list si:arg1 si:arg2))
+       ((= 3 si:argn)
+        (list si:arg1 si:arg2 si:arg3))
+       ((= 4 si:argn)
+        (list si:arg1 si:arg2 si:arg3 si:arg4))
+       ((= 5 si:argn)
+        (list si:arg1 si:arg2 si:arg3 si:arg4 si:arg5))
+       ((= 6 si:argn)
+        (list si:arg1 si:arg2 si:arg3 si:arg4 si:arg5 si:arg6))
+       ((= 7 si:argn)
+        (list si:arg1 si:arg2 si:arg3 si:arg4 si:arg5 si:arg6
+              si:arg7))
+       ((= 8 si:argn)
+        (list si:arg1 si:arg2 si:arg3 si:arg4 si:arg5 si:arg6
+              si:arg7 si:arg8))
+       ((> si:argn 8)
+        (rplacd (nthcdr (- si:argn 9) si:arglist) nil)
+        (list* si:arg1 si:arg2 si:arg3 si:arg4 si:arg5 si:arg6
+               si:arg7 si:arg8 si:arglist))
+       (t (ferror () "Internal error, si:argn = ~D" si:argn))))
+\f
+(defun union (set &rest others)
+  (loop for s in others
+       do (loop for elt in s
+                unless (memq elt set)
+                do (push elt set))
+       finally (return set)))
+
+(defun make-list (length &rest options &aux (iv))
+  (loop for (key val) on options by #'cddr
+       do (selectq key
+            (:initial-value
+               (setq iv val))
+            (:area)
+            (otherwise
+             (error "Illegal parameter to make-list" key))))
+  (loop for i from 1 to length collect iv))
+\f
+;; si:printing-random-object
+;; A macro for aiding in the printing of random objects.
+;; This macro generates a form which: (by default) includes the virtual 
+;; address in the printed representation.
+;; Options are :NO-POINTER to suppress the pointer
+;;             :TYPEP princs the typep of the object first.
+
+;; Example:
+;; (DEFSELECT ((:PROPERTY HACKER :NAMED-STRUCTURE-INVOKE))
+;;   (:PRINT-SELF (HACKER STREAM IGNORE IGNORE)
+;;     (SI:PRINTING-RANDOM-OBJECT (HACKER STREAM :TYPEP)
+;;       (PRIN1 (HACKER-NAME HACKER) STREAM))))
+;; ==> #<HACKER /"MMcM/" 6172536765>
+
+(defmacro si:printing-random-object ((object stream . options) &body body)
+  (let ((%pointer t)
+       (typep nil))
+    (do ((l options (cdr l)))
+       ((null l))
+      (selectq (car l)
+       (:no-pointer (setq %pointer nil))
+       (:typep (setq typep t))
+       (:fastp (setq l (cdr l)))               ; for compatibility sake
+       (otherwise
+        (ferror nil "~S is an unknown keyword in si:printing-random-object"
+                (car l)))))
+    `(progn
+       (patom "#<" ,stream)
+       ,@(and typep
+             `((patom (:typep ,object) ,stream)))
+       ,@(and typep body
+             `((patom " " ,stream)))
+       ,@body
+       ,@(and %pointer
+             `((patom " " ,stream)
+               (patom (maknum ,object) ,stream)))
+       (patom ">" ,stream)
+       ,object)))
+\f
+(defun named-structure-p (x &aux symbol)
+  (cond ((or (and (hunkp x) (atom (setq symbol (cxr 0 x))))
+            (and (vectorp x)
+                 (setq symbol (or (and (atom (vprop x)) (vprop x))
+                                  (and (dtpr (vprop x))
+                                       (atom (car (vprop x)))
+                                       (car (vprop x)))))))
+                                 
+        (if (get symbol 'defstruct-description)
+            symbol))))
+
+(defun named-structure-symbol (x)
+  (or (named-structure-p x)
+      (ferror () "~S was supposed to have been a named structure."
+             x)))
+
+(declare (localf named-structure-invoke-internal))
+
+(defun named-structure-invoke (operation struct &rest args)
+  (named-structure-invoke-internal operation struct args t))
+
+(defun named-structure-invoke-carefully (operation struct &rest args)
+  (named-structure-invoke-internal operation struct args nil))
+
+(defun named-structure-invoke-internal (operation struct args error-p)
+   (let (symbol fun)
+      (setq symbol (named-structure-symbol struct))
+      (if (setq fun (get symbol ':named-structure-invoke))
+        then (lexpr-funcall fun operation struct args)
+        else (and error-p
+                  (ferror ()
+                          "No named structure invoke function for ~S"
+                          struct)))))
+
+(defmacro defselect ((function-spec default-handler no-which-operations)
+                    &rest args)
+  (let ((name (intern (gensym)))
+       fun-name)
+    `(progn 'compile
+       (defun ,(if (eq (car function-spec) ':property)
+                  (cdr function-spec)
+                  (ferror () "Can't interpret ~S defselect function spec"
+                                 function-spec))
+             (operation &rest args &aux temp)
+        (if (setq temp (gethash operation (get ',name 'select-table)))
+            (lexpr-funcall temp args)
+            ,(if default-handler
+                 `(lexpr-funcall ,default-handler operation args)
+                 `(ferror () "No handler for the ~S method of ~S"
+                          operation ',function-spec))))
+       (setf (get ',name 'select-table) (make-hash-table))
+       ,@(do ((args args (cdr args))
+            (form)
+            (forms nil))
+           ((null args) (nreverse forms))
+         (setq form (car args))
+         (cond ((atom (cdr form))
+                (setq fun-name (cdr form)))
+               (t (setq fun-name
+                        (intern (concat name (if (atom (car form)) (car form)
+                                                 (caar form)))))
+                  (push `(defun ,fun-name ,@(cdr form)) forms)))
+         (if (atom (car form))
+             (push `(puthash ',(car form) ',fun-name
+                             (get ',name 'select-table))
+                   forms)
+             (mapc #'(lambda (q)
+                       (push `(puthash ',q ',fun-name
+                                       (get ',name 'select-table))
+                             forms))
+                   (car form))))
+       ,@(and (not no-which-operations)
+             `((defun ,(setq fun-name (intern
+                                       (concat name '-which-operations)))
+                      (&rest args)
+                 '(:which-operations ,@(loop for form in args
+                                             appending (if (atom (car form))
+                                                           (list (car form))
+                                                           (car form)))))
+               (puthash ':which-operations ',fun-name
+                        (get ',name 'select-table))))
+       ',function-spec)))
+\f
+(defun :typep (ob &optional (type nil) &aux temp)
+  (cond ((instancep ob)
+        (instance-typep ob type))
+       ((setq temp (named-structure-p ob))
+        (if (null type) temp
+            (if (eq type temp) t
+                (memq type (nth 11. (get temp 'defstruct-description))))))
+       ((hunkp ob)
+        (if (null type) 'hunk (eq type 'hunk)))
+       ((null type)
+        (funcall 'typep ob))
+       (t (eq type (funcall 'typep ob)))))
+
+(defun send-internal (object message &rest args)
+  (declare (special .own-flavor. self))
+  (lexpr-funcall (if (eq self object)
+                    (or (gethash message
+                                 (flavor-method-hash-table .own-flavor.))
+                        (flavor-default-handler .own-flavor.))
+                    object)
+                message args))
+\f
+;; New printer
+
+(declare (special poport prinlevel prinlength top-level-print))
+
+(defun zprint (x &optional (stream poport))
+       (zprin1 x stream)
+       't)
+
+(defun zprinc (x &optional (stream poport))
+       (zprin1a x stream () (or prinlevel -1)))
+
+(defun zprin1 (x &optional (stream poport))
+       (zprin1a x stream 't (or prinlevel -1)))
+
+(defun zprin1a (ob stream slashifyp level &aux temp)
+  (cond ((null ob) (patom "()" stream))
+       ((setq temp (named-structure-p ob))
+        (or (named-structure-invoke-carefully ':print-self ob stream
+                                               level slashifyp)
+            (si:printing-random-object (ob stream :typep))))
+       ((instancep ob)
+        (if (get-handler-for ob ':print-self)
+            (send ob ':print-self stream)
+            (si:printing-random-object (ob stream :typep))))
+        ((atom ob)
+        (if slashifyp (xxprint ob stream)
+            (patom ob stream)))
+       ((dtpr ob) (zprint-list ob stream slashifyp (1- level)))
+       ((hunkp ob) (zprint-hunk ob stream slashifyp (1- level)))
+       ((= level 0)
+        (patom "&" stream))
+       (t
+        (if slashifyp (xxprint ob stream)
+            (patom ob stream))))
+  't)
+
+(defun zprint-list (l stream slashifyp level)
+       (tyo #/( stream)
+       (do ((l l (cdr l))
+           (i (or prinlength -1) (1- i))
+           (first t nil))
+          ((not (dtpr l))
+           (cond ((not (null l))
+                  (patom " . " stream)
+                  (zprin1a l stream slashifyp level)))
+           't)
+           (cond ((= i 0)
+                 (patom " ..." stream)
+                 (return 't)))
+          (if (not first)
+              (tyo #/  stream))
+          (zprin1a (car l) stream slashifyp level))
+       (tyo #/) stream))
+
+(defun zprint-hunk (l stream slashifyp level)
+       (tyo #/{ stream)
+       (do ((i 0 (1+ i))
+           (lim (hunksize l))
+           (first t nil))
+          ((= i lim)
+           't)
+           (cond ((and (not (null prinlength)) (not (< i prinlength)))
+                 (patom " ..." stream)
+                 (return 't)))
+          (if (not first)
+              (tyo #/  stream))
+          (zprin1a (cxr i l) stream slashifyp level))
+       (tyo #/} stream))
+
+(eval-when (load eval)
+   (putd 'xxprint (getd 'print))
+   (putd 'xxprinc (getd 'princ)))
+
+(defun new-printer ()
+  (setq top-level-print 'zprint)
+  (putd 'print (getd 'zprint))
+  (putd 'prin1 (getd 'zprin1))
+  't)
+
+(defun old-printer ()
+  (setq top-level-print 'xxprint)
+  (putd 'print (getd 'xxprint))
+  (putd 'princ (getd 'xxprinc))
+  't)
+
+
+
+
+(putprop 'lmhacks t 'version)
diff --git a/usr/src/ucb/lisp/lisplib/macros.l b/usr/src/ucb/lisp/lisplib/macros.l
new file mode 100644 (file)
index 0000000..ff577fe
--- /dev/null
@@ -0,0 +1,710 @@
+(setq rcs-macros-
+   "$Header: macros.l,v 1.4 83/09/12 15:24:08 layer Exp $")
+
+;; macros.l                            -[Mon Aug 15 10:41:25 1983 by jkf]-
+;;
+;;  The file contains the common macros for Franz lisp.
+;; contents:
+;;     defmacro
+;;     setf
+;;     defsetf
+;;     push
+;;     pop
+;;     let
+;;     let*
+;;     caseq
+;;     listify
+;;     include-if
+;;     includef-if
+;;     defvar
+
+
+(declare (macros t))
+
+;; defmacro
+(declare (special defmacrooptlist protect-list protect-evform))
+
+;--- defmacro - name - name of macro being defined
+;            - pattrn - formal arguments plus other fun stuff
+;            - body   - body of the macro
+; This is an intellegent macro creator.  The pattern may contain
+; symbols which are formal paramters, lists which show how the
+; actual paramters will appear in the args, and these key words
+;  &rest name  - the rest of the args (or nil if there are no other args)
+;               is bound to name
+;  &optional name - bind the next arg to name if it exists, otherwise
+;                  bind it to nil
+;  &optional (name init) - bind the next arg to name if it exists, otherwise
+;                  bind it to init evaluted. (the evaluation is done left
+;                  to right for optional forms)
+;  &optional (name init given) - bind the next arg to name and given to t
+;                  if the arg exists, else bind name to the value of
+;                  init and given to nil.
+;  &aux name
+;  &aux (name init)
+;
+; Method of operation:
+;  the list returned from defmcrosrc has the form ((cxxr name) ...)
+;      where cxxr is the loc of the macro arg and name is it formal name
+;  defmcrooptlist has the form ((initv cxxr name) ...)
+; which is use for &optional args with an initial value.
+;  here cxxr looks like cdd..dr which will test of the arg exists.
+;
+; the variable defmacro-for-compiling determines if the defmacro forms
+; will be compiled. If it is t, then we return (progn 'compile (def xx..))
+; to insure that it is compiled
+;
+(declare (special defmacro-for-compiling))
+(cond ((null (boundp 'defmacro-for-compiling))   ; insure it has a value
+       (setq defmacro-for-compiling nil)))
+
+(def defmacro
+  (macro (args)
+    ((lambda 
+       (tmp tmp2 defmacrooptlist body protect-evform protect-list gutz)
+       (setq tmp (defmcrosrch (caddr args) '(d r) nil)
+            body
+            `(def ,(cadr args)
+                  (macro (defmacroarg)
+                    ((lambda ,(mapcar 'cdr tmp)
+                             ,@(mapcar 
+                                  '(lambda (arg)
+                                     `(cond ((setq ,(caddr arg)
+                                                   (,(cadr arg) 
+                                                     defmacroarg))
+                                             ,@(cond ((setq tmp2 (cadddr arg))
+                                                      `((setq ,tmp2 t))))
+                                             (setq ,(caddr arg)
+                                                   (car ,(caddr arg))))
+                                            (t (setq ,(caddr arg)
+                                                     ,(car arg)))))
+                                       defmacrooptlist)
+                             ,@(cond (protect-evform 
+                                      (setq gutz 
+                                            (eval `((lambda ,(mapcar 'cdr tmp)
+                                                            ,@(cdddr args))
+                                                    ,@(mapcar
+                                                       '(lambda (x) `',(cdr x))
+                                                       tmp))))
+                                      (ncons 
+                                       `(cond (,protect-evform
+                                                     (copy
+                                                        `((lambda ,',(mapcar 'cdr tmp)
+                                                             ,',gutz)
+                                                          ,,@(mapcar 'cdr tmp))))
+                                              (t ,@(cdddr args)))))
+                                     (t (cdddr args))))
+                     ,@(mapcar '(lambda (arg) 
+                                        (cond ((dtpr (car arg))
+                                               (caar arg))
+                                              ((car arg)
+                                               `(,(car arg) defmacroarg))))
+                              tmp)))))
+      (cond (defmacro-for-compiling `(progn 'compile ,body))
+           (t body)))
+
+     nil nil nil nil nil nil nil)))
+
+(def defmcrosrch
+  (lambda (pat form sofar)
+         (cond ((null pat) sofar)
+               ((atom pat) (cons (cons (concatl `(c ,@form)) pat)
+                                 sofar))
+               ((memq (car pat) '(&rest &body))
+                (append (defmcrosrch (cadr pat) form nil)
+                        (defmcrosrch (cddr pat) form sofar)))
+               ((eq (car pat) '&optional)
+                (defmcrooption (cdr pat) form sofar))
+               ((eq (car pat) '&protect)
+                (setq protect-list (cond ((atom (cadr pat))
+                                          (ncons (cadr pat)))
+                                         (t (cadr pat)))
+                      protect-evform (cons 'or (mapcar '(lambda (x)
+                                                                `(dtpr ,x))
+                                                       protect-list)))
+                (defmcrosrch (cddr pat) form sofar))
+               ((eq (car pat) '&aux)
+                (mapcar '(lambda (frm)
+                                 (cond ((atom frm) `((nil) . ,frm))
+                                       (t `((,(cadr frm)) . ,(car frm)))))
+                        (cdr pat)))
+               (t (append (defmcrosrch (car pat) (cons 'a form) nil)
+                          (defmcrosrch (cdr pat) (cons 'd form) sofar))))))
+
+(def defmcrooption
+  (lambda (pat form sofar)
+    ((lambda (tmp tmp2)
+         (cond ((null pat) sofar)
+               ((memq (car pat) '(&rest &body))
+                (defmcrosrch (cadr pat) form sofar))
+               (t (cond ((atom (car pat))
+                         (setq tmp (car pat)))
+                        (t (setq tmp (caar pat))
+                           (setq defmacrooptlist 
+                                 `((,(cadar pat) 
+                                       ,(concatl `(c ,@form))
+                                       ,tmp
+                                       ,(setq tmp2 (caddar pat)))
+                                   . ,defmacrooptlist))))
+                  (defmcrooption 
+                       (cdr pat) 
+                       (cons 'd form) 
+                       `( (,(concatl `(ca ,@form)) . ,tmp)
+                          ,@(cond (tmp2 `((nil . ,tmp2))))
+                         . ,sofar)))))
+     nil nil)))
+
+
+;--- lambdacvt :: new lambda converter.
+;
+; - input is  a lambda body beginning with the argument list.
+;
+; vrbls   :: list of (name n) where n is the arg number for name
+; optlist :: list of (name n defval pred) where optional variable name is
+;           (arg n) [if it exists], initval is the value if it doesn't
+;           exist,  pred is set to non nil if the arg exists
+; auxlist :: list of (name initial-value) for auxillary variables. (&aux)
+; restform :: (name n) where args n to #args should be consed and assigned
+;              to name.
+;
+;; strategy:
+;  Until the compiler can compiler lexprs better, we try to avoid creating
+; a lexpr.  A lexpr is only required if &optional or &rest forms
+; appear.
+;   Formal parameters which come after &aux are bound and evaluated in a let*
+; surrounding the body.  The parameter after a &rest is put in the let*
+; too, with an init form which is a complex do loop.  The parameters
+; after &optional are put in the lambda expression just below the lexpr.
+;
+(defun lambdacvt (exp)
+   (prog (vrbls optlist auxlist restform vbl fl-type optcode mainvar
+         minargs maxargs)
+      (do ((reallist (car exp) (cdr reallist))
+          (count 1 (1+ count)))
+         ((null reallist))
+         (setq vbl (car reallist))
+         (cond ((memq vbl '(&rest &body))
+                (setq fl-type '&rest count (1- count)))
+               ((eq '&aux vbl)
+                (setq fl-type '&aux count (1- count)))
+               ((eq '&optional vbl)
+                (setq fl-type '&optional count (1- count)))
+               ((null fl-type)          ; just a variable
+                (setq vrbls (cons (list vbl count) vrbls)))
+               ((eq fl-type '&rest)
+                (cond (restform (error "Too many &rest parameters " vbl)))
+                (setq restform (list vbl count)))
+               ((eq fl-type '&aux)
+                (cond ((atom vbl)
+                       (setq auxlist (cons (list vbl nil) auxlist)))
+                      (t (setq auxlist (cons (list (car vbl) (cadr vbl))
+                                             auxlist)))))
+               ((eq fl-type '&optional)
+                (cond ((atom vbl)
+                       (setq optlist
+                             (cons (list vbl count) optlist)))
+                      (t (setq optlist
+                               (cons (cons (car vbl)
+                                           (cons count
+                                                 (cdr vbl)))
+                                     optlist)))))))
+
+      ;; arguments are collected in reverse order, but set them straight
+      (setq vrbls (nreverse vrbls)
+           optlist (nreverse optlist)
+           auxlist (nreverse auxlist)
+           minargs (length vrbls)
+           maxargs (cond (restform nil)
+                         (t (+ (length optlist) minargs))))
+
+      ;; we must covert to a lexpr if there are &optional or &rest forms
+      (cond ((or optlist restform) (setq mainvar (gensym))))
+      
+      ; generate optionals code
+      (cond (optlist
+              (setq optcode
+                    (mapcar '(lambda (x)
+                                `(cond ((> ,(cadr x) ,mainvar)
+                                        (setq ,(car x) ,(caddr x)))
+                                       (t (setq ,(car x)
+                                                 (arg ,(cadr x)))
+                                          ,(cond ((cdddr x)
+                                                  `(setq ,(cadddr x) t))))))
+                            optlist))))
+
+      ;; do the rest forms
+      (cond (restform
+              (let ((dumind (gensym))
+                    (dumcol (gensym)))
+                 (setq restform
+                       `((,(car restform)
+                           (do ((,dumind ,mainvar (1- ,dumind))
+                                (,dumcol nil (cons (arg ,dumind) ,dumcol)))
+                               ((< ,dumind ,(cadr restform)) ,dumcol))))))))
+      
+      ;; calculate body
+      (let (body)
+        (setq body (cond ((or auxlist restform)
+                            `((let* ,(append restform auxlist)
+                                 ,@(cdr exp))))
+                         (t (cdr exp))))
+        (cond ((null mainvar)          ; no &optional or &rest
+               (return `(lambda ,(mapcar 'car vrbls)
+                           (declare (*args ,minargs ,maxargs))
+                           ,@body)))
+              (t (return
+                    `(lexpr (,mainvar)
+                        (declare (*args ,minargs ,maxargs))
+                        ((lambda
+                            ,(nconc
+                                (mapcar 'car vrbls)
+                                (mapcan '(lambda (x)   ; may be two vrbls
+                                            (cons (car x)
+                                                  (cond ((cdddr x) ;pred?
+                                                         (ncons
+                                                            (cadddr x))))))
+                                        optlist))
+                            ,@optcode ,@body)
+                         ,@(nconc (mapcar '(lambda (x) `(arg ,(cadr x)))
+                                          vrbls)
+                                  (mapcan '(lambda (x)
+                                              (cond ((cdddr x)
+                                                     (list nil nil))
+                                                    (t (list nil))))
+                                          optlist))))))))))
+
+;--- defcmacro :: like defmacro but result ends up under cmacro ind
+;
+(def defcmacro
+   (macro (args)
+       (let ((name (concat (cadr args) "::cmacro:" (gensym))))
+          `(eval-when (compile load eval)
+                   (defmacro ,name ,@(cddr args))
+                   (putprop ',(cadr args) (getd ',name) 'cmacro)
+                   (remob ',name)))))
+
+;;; --- setf macro
+;
+;(setf (cadr x) 3) --> (rplaca (cdr x) 3)
+
+(defmacro setf (expr val &rest rest)
+         (cond ((atom expr)
+                (or (symbolp expr)
+                    (error '|-- setf can't handle this.| expr))
+                `(setq ,expr ,val))
+               (t
+                (do ((y)) (())
+                    (or (symbolp (car expr))
+                        (error '|-- setf can't handle this.| expr))
+                    (and (setq y (get (car expr) 'setf-expand))
+                         (return (apply y `(,expr ,val ,@rest))))
+                    (or (setf-check-cad+r (car expr))
+                        (and
+                           (or (setq y (get (car expr) 'cmacro))
+                               (setq y (getd (car expr))))
+                           (or (and (dtpr y)
+                                    (eq (car y) 'macro))
+                               (and (bcdp y)
+                                    (eq (getdisc y) 'macro)))
+                           (setq expr (apply y expr)))
+                        (error '|-- setf can't handle this.| expr))))))
+
+(defun setf-check-cad+r (name)
+   (if (eq (getcharn name 1) #/c)
+      then (let ((letters (nreverse (cdr (exploden name)))))
+             (if (eq (car letters) #/r)
+                then (do ((xx (cdr letters) (cdr xx)))
+                         ((null xx)
+                          ;; form is c{ad}+r, setf form is
+                          ;; (rplac<first a or d> (c<rest of a's + d's>r x))
+                          (setq letters (nreverse letters))
+                          (eval
+                             `(defsetf ,name (e v)
+                                 (list
+                                    ',(concat "rplac" (ascii (car letters)))
+                                     (list
+                                        ',(implode `(#/c ,@(cdr letters)))
+                                        (cadr e))
+                                     v)))
+                          t)
+                         (if (not (memq (car xx) '(#/a #/d)))
+                             then (return nil)))))))
+                                          
+(defmacro defsetf (name vars &rest body)
+         `(eval-when 
+           (compile load eval)
+           (defun (,name setf-expand) ,vars . ,body)))
+
+;--- other setf's for car's and cdr's are generated automatically
+;
+(defsetf car (e v) `(rplaca ,(cadr e) ,v))
+(defsetf caar (e v) `(rplaca (car ,(cadr e)) ,v))
+(defsetf cadr (e v) `(rplaca (cdr ,(cadr e)) ,v))
+(defsetf cdr (e v) `(rplacd ,(cadr e) ,v))
+(defsetf cdar (e v) `(rplacd (car ,(cadr e)) ,v))
+(defsetf cddr (e v) `(rplacd (cdr ,(cadr e)) ,v))
+(defsetf cxr (e v) `(rplacx ,(cadr e) ,(caddr e) ,v))
+
+(defsetf vref (e v) `(vset ,(cadr e) ,(caddr e) ,v))
+(defsetf vrefi-byte (e v) `(vseti-byte ,(cadr e) ,(caddr e) ,v))
+(defsetf vrefi-word (e v) `(vseti-word ,(cadr e) ,(caddr e) ,v))
+(defsetf vrefi-long (e v) `(vseti-long ,(cadr e) ,(caddr e) ,v))
+
+(defsetf nth (e v) `(rplaca (nthcdr ,(cadr e) ,(caddr e)) ,v))
+(defsetf nthelem (e v) `(rplaca (nthcdr (1- ,(cadr e)) ,(caddr e)) ,v))
+(defsetf nthcdr (e v) `(rplacd (nthcdr (1- ,(cadr e)) ,(caddr e)) ,v))
+
+(defsetf arraycall (e v) `(store ,e ,v))
+(defsetf get (e v) `(putprop ,(cadr e) ,v ,(caddr e)))
+
+(defsetf plist (e v) `(setplist ,(cadr e) ,v))
+
+(defsetf symeval (e v) `(set ,(cadr e) ,v))
+
+(defsetf arg (e v) `(setarg ,(cadr e) ,v))
+
+(defsetf args (e v) `(args ,(cadr e) ,v))
+
+
+(defmacro push (object list) `(setf ,list (cons ,object ,list)))
+
+; this relies on the fact that setf returns the value stored.
+(defmacro pop (list &optional (into nil into-p))
+  (cond (into-p `(prog1 (setf ,into (car ,list))
+                        (setf ,list (cdr ,list))))
+        (t `(prog1 (car ,list)
+                   (setf ,list (cdr ,list))))))
+
+; let for franz (with destructuring)
+;--- let
+;      - binds - binding forms
+;      - . body - forms to execute
+; the binding forms may have these forms
+;   a  local variable a, initially nil
+;  (a x)  local variable a, x is evaled and a gets its value initially
+;  ((a . (b . c)) x)   three local variables, a,b and c which are given
+;                      values corresponding to the location in the value
+;                      of x.  Any structure is allowed here. 
+;
+(defmacro let (binds &rest body &aux vrbls vals destrs newgen)
+  (mapc '(lambda (form)
+               (cond ((atom form)
+                      (setq vrbls (cons form vrbls)
+                            vals  (cons nil vals)))
+                     ((atom (car form))
+                      (setq vrbls (cons (car form) vrbls)
+                            vals  (cons (cadr form) vals)))
+                     (t (setq newgen (gensym)
+                              destrs `((,newgen ,@(de-compose (car form) '(r)))
+                                       ,@destrs)
+                              vrbls  (cons newgen vrbls)
+                              vals   (cons (cadr form) vals)))))
+       binds)
+
+  (mapc '(lambda (frm)
+               (do ((ll (cdr frm) (cdr ll)))
+                   ((null ll))
+                   (setq vrbls (cons (cdar ll) vrbls)
+                         vals  (cons nil vals))))
+       destrs)
+
+  (setq vals (nreverse vals)
+       vrbls (nreverse vrbls)
+       destrs (nreverse destrs))
+  `((lambda ,vrbls
+           ,@(mapcan '(lambda (frm)
+                              (mapcar '(lambda (vrb)
+                                               `(setq ,(cdr vrb) (,(car vrb)
+                                                                 ,(car frm))))
+                                      (cdr frm)))
+                     destrs)
+           ,@body)
+    ,@vals))
+
+;--- de-compose
+;              form - pattern to de-compose
+;              sofar - the sequence of cxxr's needed to get to this part
+;                      of the pattern
+;  de-compose returns a list of this form
+;
+;      ((cxxr . a) (cyyr . b) ... )
+; which tells how to get to the value for a and b ..etc..
+;
+(def de-compose 
+  (lambda (form sofar)
+         (cond ((null form ) nil)
+               ((atom form) (ncons (cons (apply 'concat (cons 'c sofar))
+                                         form)))
+               (t (nconc (de-compose (car form) (cons 'a sofar))
+                         (de-compose (cdr form) (cons 'd sofar)))))))
+
+;--- caseq
+; use is 
+;    (caseq expr
+;          (match1 do1)
+;          (match2 do2)
+;          (t  doifallelsefails))
+; the matchi can be atoms in which case an 'eq' test is done, or they
+; can be lists in which case a 'memq' test is done.
+;
+
+(defmacro caseq (switch &body clauses &aux var code)
+   (setq var (cond ((symbolp switch) switch) ((gensym 'Z))))
+   (setq code
+        `(cond . ,(mapcar '(lambda (clause)
+                              (cons
+                                 (let ((test (car clause)))
+                                    (cond ((eq test t) t)
+                                          ((dtpr test)
+                                           `(memq ,var ',test))
+                                          (t `(eq ,var ',test))))
+                                 (cdr clause)))
+                          clauses)))
+   (cond ((symbolp switch) code)
+        (`((lambda (,var) ,code) ,switch))))
+
+;--- selectq :: just like caseq
+; except 'otherwise' is recogized as equivalent to 't' as a key
+;
+(defmacro selectq (key . forms)
+         (setq forms
+               (mapcar '(lambda (form) (if (eq (car form) 'otherwise)
+                                            (cons t (cdr form)) form))
+                       forms))
+         `(caseq ,key . ,forms))
+
+;--- let*
+;      - binds  - binding forms (like let)
+;      - body   - forms to eval (like let)
+; this is the same as let, except forms are done in a left to right manner
+; in fact, all we do is generate nested lets
+;
+(defmacro let* (binds &rest body)
+  (do ((ll (reverse binds) (cdr ll)))
+      ((null ll) (car body))
+      (setq body `((let (,(car ll)) ,@body)))))
+
+
+                  
+;--- listify : n  - integer
+;      returns a list of the first n args to the enclosing lexpr if
+; n is positive, else returns the last -n args to the lexpr if n is
+; negative.
+; returns nil if n is 0
+;
+(def listify 
+  (macro (lis)
+        `(let ((n ,(cadr lis)))
+              (cond ((eq n 0) nil)
+                    ((minusp n)
+                     (do ((i (arg nil)  (1- i))
+                          (result nil (cons (arg i) result)))
+                         ((<& i (+ (arg nil) n  1)) result) ))
+                    (t (do ((i n  (1- i))
+                            (result nil (cons (arg i) result)))
+                           ((<& i 1) result) ))))))
+
+;--- include-if
+; form: (include-if <predicate> <filename>)
+;  will return (include <filename>) if <predicate> is non-nil
+;  This is useful at the beginning of a file to conditionally
+;  include a file based on whether it has already been included.
+;
+(defmacro include-if (pred filename)
+   (cond ((eval pred) `(include ,filename))))
+
+;--- includef-if
+; form: (includef-if <predicate> '<filename>)
+;  like the above except it includef's the file.
+;
+(defmacro includef-if (pred filenameexpr)
+   (cond ((eval pred) `(includef ,filenameexpr))))
+
+;--- if :: macro for doing conditionalization
+;
+;  This macro is compatible with both the crufty mit-version and
+; the keyword version at ucb.
+;
+;  simple summary:
+;   non-keyword use:
+;      (if a b) ==> (cond (a b))
+;      (if a b c d e ...) ==> (cond (a b) (t c d e ...))
+;   with keywords:
+;      (if a then b) ==> (cond (a b))
+;      (if a thenret) ==> (cond (a))
+;      (if a then b c d e) ==> (cond (a b c d e))
+;      (if a then b c  else d) ==> (cond (a b c) (t d))
+;      (if a then b c  elseif d  thenret  else g)
+;              ==> (cond (a b c) (d) (t g))
+;
+;   
+;
+;
+; In the syntax description below,
+;    optional parts are surrounded by [ and ],
+;    + means one or more instances.
+;    | means 'or'
+;    <expr> is an lisp expression which isn't a keyword
+;       The keywords are:  then, thenret, else, elseif.
+;    <pred> is also a lisp expression which isn't a keyword.
+; 
+; <if-stmt> ::=  <simple-if-stmt>
+;             | <keyword-if-stmt>
+; 
+; <simple-if-stmt> ::=  (if <pred> <expr>)
+;                    | (if <pred> <expr> <expr>)
+; 
+; <keyword-if-stmt> ::= (if <pred> <then-clause> [ <else-clause> ] )
+; 
+; <then-clause> ::=  then <expr>+
+;                 | thenret
+; 
+; <else-clause> ::=  else <expr>+
+;                 | elseif <pred> <then-clause> [ <else-clause> ]
+;
+
+(declare (special if-keyword-list))
+
+(eval-when (compile load eval)
+   (setq if-keyword-list '(then thenret elseif else)))
+
+;--- if
+;
+;  the keyword if expression is parsed using a simple four state
+; automaton.  The expression is parsed in reverse.
+; States:
+;      init - have parsed a complete predicate,  then clause
+;      col  - have collected at least one non keyword in col
+;      then - have just seen a then, looking for a predicate
+;      compl - have just seen a predicate after an then, looking
+;              for elseif or if (i.e. end of forms).
+;
+(defmacro if (&rest args)
+   (let ((len (length args)))
+      ;; first eliminate the non-keyword if macro cases
+      (cond ((<& len 2)
+            (error "if: not enough arguments " args))
+           ((and (=& len 2)
+                 (not (memq (cadr args) if-keyword-list)))
+            `(cond (,(car args) ,(cadr args))))
+           ; clause if there are not keywords (and len > 2)
+           ((do ((xx args (cdr xx)))
+                ((null xx) t)
+                (cond ((memq (car xx) if-keyword-list)
+                       (return nil))))
+            `(cond (,(car args) ,(cadr args))
+                   (t ,@(cddr args))))
+           
+           ;; must be an instance of a keyword if macro
+           
+           (t (do ((xx (reverse args) (cdr xx))
+                   (state 'init)
+                   (elseseen nil)
+                   (totalcol nil)
+                   (col nil))
+                  ((null xx)
+                   (cond ((eq state 'compl)
+                          `(cond ,@totalcol))
+                         (t (error "if: illegal form " args))))
+                  (cond ((eq state 'init)
+                         (cond ((memq (car xx) if-keyword-list)
+                                (cond ((eq (car xx) 'thenret)
+                                       (setq col nil
+                                             state 'then))
+                                      (t (error "if: bad keyword "
+                                                (car xx) args))))
+                               (t (setq state 'col
+                                        col nil)
+                                  (push (car xx) col))))
+                        ((eq state 'col)
+                         (cond ((memq (car xx) if-keyword-list)
+                                (cond ((eq (car xx) 'else)
+                                       (cond (elseseen
+                                                (error
+                                                   "if: multiples elses "
+                                                   args)))
+                                       (setq elseseen t)
+                                       (setq state 'init)
+                                       (push `(t ,@col) totalcol))
+                                      ((eq (car xx) 'then)
+                                       (setq state 'then))
+                                      (t (error "if: bad keyword "
+                                                (car xx) args))))
+                               (t (push (car xx) col))))
+                        ((eq state 'then)
+                         (cond ((memq (car xx) if-keyword-list)
+                                (error "if: keyword at the wrong place "
+                                       (car xx) args))
+                               (t (setq state 'compl)
+                                  (push `(,(car xx) ,@col) totalcol))))
+                        ((eq state 'compl)
+                         (cond ((not (eq (car xx) 'elseif))
+                                (error "if: missing elseif clause " args)))
+                         (setq state 'init))))))))
+
+;--- If :: the same as 'if' but defined for those programs that still
+;      use it.
+;
+(putd 'If (getd 'if))
+
+;--- defvar :: a macro for declaring a variable special
+;  a variable declared special with defvar will be special when the
+; file containing the variable is compiled and also when the file
+; containing the defvar is loaded in.  Furthermore, you can specify
+; an default value for the variable. It will be set to that value
+; iff it is unbound
+;
+(defmacro defvar (variable &optional (initial-value nil iv-p) documentation)
+  (if iv-p
+     then `(progn 'compile
+                  (eval-when (eval compile load)
+                         (eval '(liszt-declare (special ,variable))))
+                  (or (boundp ',variable) (setq ,variable ,initial-value)))
+     else `(eval-when (eval compile load)
+                 (eval '(liszt-declare (special ,variable))))))
+
+
+
+
+(defmacro list* (&rest forms)
+         (cond ((null forms) nil)
+               ((null (cdr forms)) (car forms))
+               (t (construct-list* forms))))
+
+(eval-when (load compile eval)
+   (defun construct-list* (forms)
+         (setq forms (reverse forms))
+         (do ((forms (cddr forms) (cdr forms))
+              (return-form `(cons ,(cadr forms) ,(car forms))
+                            `(cons ,(car forms) ,return-form)))
+             ((null forms) return-form))))
+
+;; (<= a b) --> (not (> a b))
+;; (<= a b c) --> (not (or (> a b) (> b c)))
+;; funny arglist to check for correct number of arguments.
+
+
+(defmacro <= (arg1 arg2 &rest rest &aux result)
+  (setq rest (list* arg1 arg2 rest))
+  (do l rest (cdr l) (null (cdr l))
+      (push `(> ,(car l) ,(cadr l)) result))
+  (cond ((null (cdr result)) `(not ,(car result)))
+       (t `(not (or . ,(nreverse result))))))
+
+(defmacro <=& (x y)
+   `(not (>& ,x ,y)))
+
+;; (>= a b) --> (not (< a b))
+;; (>= a b c) --> (not (or (< a b) (< b c)))
+;; funny arglist to check for correct number of arguments.
+
+(defmacro >= (arg1 arg2 &rest rest &aux result)
+  (setq rest (list* arg1 arg2 rest))
+  (do l rest (cdr l) (null (cdr l))
+      (push `(< ,(car l) ,(cadr l)) result))
+  (cond ((null (cdr result)) `(not ,(car result)))
+       (t `(not (or . ,(nreverse result))))))
+
+
+(defmacro >=& (x y)
+   `(not (<& ,x ,y)))
diff --git a/usr/src/ucb/lisp/lisplib/manual/ch0.r b/usr/src/ucb/lisp/lisplib/manual/ch0.r
new file mode 100644 (file)
index 0000000..6b034de
--- /dev/null
@@ -0,0 +1,325 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                   The FRANZ LISP Manual
+
+                             by
+
+
+                      _\bJ_\bo_\bh_\bn _\bK_\b. _\bF_\bo_\bd_\be_\br_\ba_\br_\bo
+
+
+                      _\bK_\be_\bi_\bt_\bh _\bL_\b. _\bS_\bk_\bl_\bo_\bw_\be_\br
+
+
+                        _\bK_\be_\bv_\bi_\bn _\bL_\ba_\by_\be_\br
+
+
+
+
+
+
+
+
+
+
+
+
+                         June 1983
+
+
+
+
+
+
+
+
+
+
+
+
+                                               A document in
+                                              four movements
+\e9
+
+\e9
+
+
+
+
+
+
+
+
+
+
+                       _\bO_\bv_\be_\br_\bt_\bu_\br_\be
+
+
+     _\bA  _\bc_\bh_\bo_\br_\bu_\bs  _\bo_\bf  _\bs_\bt_\bu_\bd_\be_\bn_\bt_\bs  _\bu_\bn_\bd_\be_\br  _\bt_\bh_\be  _\bd_\bi_\br_\be_\bc_\bt_\bi_\bo_\bn  _\bo_\bf
+     _\bR_\bi_\bc_\bh_\ba_\br_\bd _\bF_\ba_\bt_\be_\bm_\ba_\bn _\bh_\ba_\bv_\be _\bc_\bo_\bn_\bt_\br_\bi_\bb_\bu_\bt_\be_\bd _\bt_\bo _\bb_\bu_\bi_\bl_\bd_\bi_\bn_\bg _\bF_\bR_\bA_\bN_\bZ
+     _\bL_\bI_\bS_\bP _\bf_\br_\bo_\bm _\ba _\bm_\be_\br_\be _\bm_\be_\bl_\bo_\bd_\by _\bi_\bn_\bt_\bo  _\ba  _\bf_\bu_\bl_\bl  _\bs_\by_\bm_\bp_\bh_\bo_\bn_\by  .
+     _\bT_\bh_\be  _\bm_\ba_\bj_\bo_\br _\bc_\bo_\bn_\bt_\br_\bi_\bb_\bu_\bt_\bo_\br_\bs _\bt_\bo _\bt_\bh_\be _\bi_\bn_\bi_\bt_\bi_\ba_\bl _\bs_\by_\bs_\bt_\be_\bm _\bw_\be_\br_\be
+     _\bM_\bi_\bk_\be _\bC_\bu_\br_\br_\by,  _\bJ_\bo_\bh_\bn  _\bB_\br_\be_\be_\bd_\bl_\bo_\bv_\be  _\ba_\bn_\bd  _\bJ_\be_\bf_\bf  _\bL_\be_\bv_\bi_\bn_\bs_\bk_\by.
+     _\bB_\bi_\bl_\bl  _\bR_\bo_\bw_\ba_\bn  _\ba_\bd_\bd_\be_\bd _\bt_\bh_\be _\bg_\ba_\br_\bb_\ba_\bg_\be _\bc_\bo_\bl_\bl_\be_\bc_\bt_\bo_\br _\ba_\bn_\bd _\ba_\br_\br_\ba_\by
+     _\bp_\ba_\bc_\bk_\ba_\bg_\be.  _\bT_\bo_\bm _\bL_\bo_\bn_\bd_\bo_\bn _\bw_\bo_\br_\bk_\be_\bd _\bo_\bn _\ba_\bn  _\be_\ba_\br_\bl_\by  _\bc_\bo_\bm_\bp_\bi_\bl_\be_\br
+     _\ba_\bn_\bd   _\bh_\be_\bl_\bp_\be_\bd  _\bi_\bn  _\bo_\bv_\be_\br_\ba_\bl_\bl  _\bs_\by_\bs_\bt_\be_\bm  _\bd_\be_\bs_\bi_\bg_\bn.   _\bK_\be_\bi_\bt_\bh
+     _\bS_\bk_\bl_\bo_\bw_\be_\br _\bh_\ba_\bs _\bc_\bo_\bn_\bt_\br_\bi_\bb_\bu_\bt_\be_\bd _\bm_\bu_\bc_\bh _\bt_\bo _\bF_\bR_\bA_\bN_\bZ _\bL_\bI_\bS_\bP, _\ba_\bd_\bd_\bi_\bn_\bg
+     _\bt_\bh_\be  _\bb_\bi_\bg_\bn_\bu_\bm _\bp_\ba_\bc_\bk_\ba_\bg_\be _\ba_\bn_\bd _\br_\be_\bw_\br_\bi_\bt_\bi_\bn_\bg _\bm_\bo_\bs_\bt _\bo_\bf _\bt_\bh_\be _\bc_\bo_\bd_\be
+     _\bt_\bo _\bi_\bn_\bc_\br_\be_\ba_\bs_\be  _\bi_\bt_\bs  _\be_\bf_\bf_\bi_\bc_\bi_\be_\bn_\bc_\by  _\ba_\bn_\bd  _\bc_\bl_\ba_\br_\bi_\bt_\by.   _\bK_\bi_\bp_\bp
+     _\bH_\bi_\bc_\bk_\bm_\ba_\bn  _\ba_\bn_\bd  _\bC_\bh_\ba_\br_\bl_\be_\bs  _\bK_\bo_\be_\bs_\bt_\be_\br _\ba_\bd_\bd_\be_\bd _\bh_\bu_\bn_\bk_\bs.  _\bM_\bi_\bt_\bc_\bh
+     _\bM_\ba_\br_\bc_\bu_\bs _\ba_\bd_\bd_\be_\bd *_\br_\bs_\be_\bt, _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk _\ba_\bn_\bd  _\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be.   _\bD_\bo_\bn
+     _\bC_\bo_\bh_\be_\bn  _\ba_\bn_\bd  _\bo_\bt_\bh_\be_\br_\bs  _\ba_\bt  _\bC_\ba_\br_\bn_\be_\bg_\bi_\be-_\bM_\be_\bl_\bl_\bo_\bn  _\bm_\ba_\bd_\be _\bs_\bo_\bm_\be
+     _\bi_\bm_\bp_\br_\bo_\bv_\be_\bm_\be_\bn_\bt_\bs _\bt_\bo  _\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be  _\ba_\bn_\bd  _\bp_\br_\bo_\bv_\bi_\bd_\be_\bd  _\bv_\ba_\br_\bi_\bo_\bu_\bs
+     _\bf_\be_\ba_\bt_\bu_\br_\be_\bs  _\bm_\bo_\bd_\be_\bl_\bl_\be_\bd  _\ba_\bf_\bt_\be_\br  _\bU_\bC_\bI/_\bC_\bM_\bU _\bP_\bD_\bP-_\b1_\b0 _\bL_\bi_\bs_\bp _\ba_\bn_\bd
+     _\bI_\bn_\bt_\be_\br_\bl_\bi_\bs_\bp  _\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt_\bs  (_\be_\bd_\bi_\bt_\bo_\br,  _\bd_\be_\bb_\bu_\bg_\bg_\be_\br,  _\bt_\bo_\bp-
+     _\bl_\be_\bv_\be_\bl).  _\bJ_\bo_\bh_\bn _\bF_\bo_\bd_\be_\br_\ba_\br_\bo _\bw_\br_\bo_\bt_\be _\bt_\bh_\be _\bc_\bo_\bm_\bp_\bi_\bl_\be_\br, _\ba_\bd_\bd_\be_\bd _\ba
+     _\bf_\be_\bw _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs, _\ba_\bn_\bd _\bw_\br_\bo_\bt_\be _\bm_\bu_\bc_\bh _\bo_\bf _\bt_\bh_\bi_\bs  _\bm_\ba_\bn_\bu_\ba_\bl.  _\bO_\bf
+     _\bc_\bo_\bu_\br_\bs_\be,  _\bo_\bt_\bh_\be_\br  _\ba_\bu_\bt_\bh_\bo_\br_\bs  _\bh_\ba_\bv_\be _\bc_\bo_\bn_\bt_\br_\bi_\bb_\bu_\bt_\be_\bd _\bs_\bp_\be_\bc_\bi_\bf_\bi_\bc
+     _\bc_\bh_\ba_\bp_\bt_\be_\br_\bs _\ba_\bs _\bi_\bn_\bd_\bi_\bc_\ba_\bt_\be_\bd.  _\bK_\be_\bv_\bi_\bn _\bL_\ba_\by_\be_\br  _\bm_\bo_\bd_\bi_\bf_\bi_\be_\bd  _\bt_\bh_\be
+     _\bc_\bo_\bm_\bp_\bi_\bl_\be_\br  _\bt_\bo  _\bp_\br_\bo_\bd_\bu_\bc_\be _\bc_\bo_\bd_\be _\bf_\bo_\br _\bt_\bh_\be _\bM_\bo_\bt_\bo_\br_\bo_\bl_\ba _\b6_\b8_\b0_\b0_\b0,
+     _\ba_\bn_\bd _\bh_\be_\bl_\bp _\bm_\ba_\bk_\be _\bF_\bR_\bA_\bN_\bZ _\bL_\bI_\bS_\bP _\bp_\ba_\bs_\bs ``_\bL_\bi_\bn_\bt''.
+     _\bT_\bh_\bi_\bs _\bm_\ba_\bn_\bu_\ba_\bl _\bm_\ba_\by _\bb_\be _\bs_\bu_\bp_\bp_\bl_\be_\bm_\be_\bn_\bt_\be_\bd _\bo_\br  _\bs_\bu_\bp_\bp_\bl_\ba_\bn_\bt_\be_\bd  _\bb_\by
+     _\bl_\bo_\bc_\ba_\bl _\bc_\bh_\ba_\bp_\bt_\be_\br_\bs _\br_\be_\bp_\br_\be_\bs_\be_\bn_\bt_\bi_\bn_\bg _\ba_\bl_\bt_\be_\br_\ba_\bt_\bi_\bo_\bn_\bs, _\ba_\bd_\bd_\bi_\bt_\bi_\bo_\bn_\bs
+     _\ba_\bn_\bd _\bd_\be_\bl_\be_\bt_\bi_\bo_\bn_\bs.  _\bW_\be _\ba_\bt _\bU._\bC. _\bB_\be_\br_\bk_\be_\bl_\be_\by _\ba_\br_\be _\bp_\bl_\be_\ba_\bs_\be_\bd _\bt_\bo
+     _\bl_\be_\ba_\br_\bn  _\bo_\bf  _\bg_\be_\bn_\be_\br_\ba_\bl_\bl_\by  _\bu_\bs_\be_\bf_\bu_\bl  _\bs_\by_\bs_\bt_\be_\bm _\bf_\be_\ba_\bt_\bu_\br_\be_\bs, _\bb_\bu_\bg
+     _\bf_\bi_\bx_\be_\bs, _\bo_\br _\bu_\bs_\be_\bf_\bu_\bl _\bp_\br_\bo_\bg_\br_\ba_\bm  _\bp_\ba_\bc_\bk_\ba_\bg_\be_\bs,  _\ba_\bn_\bd  _\bw_\be  _\bw_\bi_\bl_\bl
+     _\ba_\bt_\bt_\be_\bm_\bp_\bt _\bt_\bo _\br_\be_\bd_\bi_\bs_\bt_\br_\bi_\bb_\bu_\bt_\be _\bs_\bu_\bc_\bh _\bc_\bo_\bn_\bt_\br_\bi_\bb_\bu_\bt_\bi_\bo_\bn_\bs.
+
+
+
+
+
+
+
+
+
+
+\e9\e8c\e9 1980, 1981, 1983 by the Regents of the University of Cali-
+fornia.   (exceptions:  Chapters 13, 14 (first half), 15 and
+16 have separate copyrights, as indicated. These are  repro-
+duced by permission of the copyright holders.)
+Permission to copy without fee all or part of this  material
+is  granted provided that the copies are not made or distri-
+buted for direct commercial  advantage,  and  the  copyright
+notice  of  the Regents, University of California, is given.
+All rights reserved.
+
+
+
+\e9
+
+
+
+
+
+
+
+
+
+
+Work reported herein was supported in  part  by  the  U.  S.
+Department  of  Energy,  Contract DE-AT03-76SF00034, Project
+Agreement DE-AS03-79ER10358, and the National Science  Foun-
+dation under Grant No.  MCS 7807291
+
+
+UNIX is a trademark of Bell Laboratories.  VAX and  PDP  are
+trademarks  of  Digital Equiptment Coporation.  MC68000 is a
+trademark of Motorola Semiconductor Products, Inc.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9
+
+
+
+
+
+
+
+
+
+
+                           Score
+
+
+
+                    First Movement (_\ba_\bl_\bl_\be_\bg_\br_\bo _\bn_\bo_\bn _\bt_\br_\bo_\bp_\bp_\bo)
+
+     1. FRANZ LISP
+          _\bI_\bn_\bt_\br_\bo_\bd_\bu_\bc_\bt_\bi_\bo_\bn _\bt_\bo _\bF_\bR_\bA_\bN_\bZ _\bL_\bI_\bS_\bP, _\bd_\be_\bt_\ba_\bi_\bl_\bs _\bo_\bf _\bd_\ba_\bt_\ba _\bt_\by_\bp_\be_\bs,
+          _\ba_\bn_\bd _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bo_\bf _\bn_\bo_\bt_\ba_\bt_\bi_\bo_\bn
+     2. Data Structure Access
+          _\bF_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bf_\bo_\br _\bt_\bh_\be _\bc_\br_\be_\ba_\bt_\bi_\bo_\bn, _\bd_\be_\bs_\bt_\br_\bu_\bc_\bt_\bi_\bo_\bn _\ba_\bn_\bd  _\bm_\ba_\bn_\bi_\b-
+          _\bp_\bu_\bl_\ba_\bt_\bi_\bo_\bn _\bo_\bf _\bl_\bi_\bs_\bp _\bd_\ba_\bt_\ba _\bo_\bb_\bj_\be_\bc_\bt_\bs.
+     3. Arithmetic Functions
+          _\bF_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bt_\bo _\bp_\be_\br_\bf_\bo_\br_\bm _\ba_\br_\bi_\bt_\bh_\bm_\be_\bt_\bi_\bc _\bo_\bp_\be_\br_\ba_\bt_\bi_\bo_\bn_\bs.
+     4. Special Functions
+          _\bF_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bf_\bo_\br _\ba_\bl_\bt_\be_\br_\bi_\bn_\bg _\bf_\bl_\bo_\bw _\bo_\bf _\bc_\bo_\bn_\bt_\br_\bo_\bl.  _\bF_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs
+          _\bf_\bo_\br _\bm_\ba_\bp_\bp_\bi_\bn_\bg _\bo_\bt_\bh_\be_\br _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bo_\bv_\be_\br _\bl_\bi_\bs_\bt_\bs.
+     5. I/O Functions
+          _\bF_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bf_\bo_\br  _\br_\be_\ba_\bd_\bi_\bn_\bg  _\ba_\bn_\bd  _\bw_\br_\bi_\bt_\bi_\bn_\bg  _\bf_\br_\bo_\bm  _\bp_\bo_\br_\bt_\bs.
+          _\bF_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs  _\bf_\bo_\br  _\bt_\bh_\be  _\bm_\bo_\bd_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn  _\bo_\bf _\bt_\bh_\be _\br_\be_\ba_\bd_\be_\br'_\bs
+          _\bs_\by_\bn_\bt_\ba_\bx.
+     6. System Functions
+          _\bF_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bf_\bo_\br _\bs_\bt_\bo_\br_\ba_\bg_\be _\bm_\ba_\bn_\ba_\bg_\be_\bm_\be_\bn_\bt,  _\bd_\be_\bb_\bu_\bg_\bg_\bi_\bn_\bg,  _\ba_\bn_\bd
+          _\bf_\bo_\br  _\bt_\bh_\be _\br_\be_\ba_\bd_\bi_\bn_\bg _\ba_\bn_\bd _\bs_\be_\bt_\bt_\bi_\bn_\bg _\bo_\bf _\bg_\bl_\bo_\bb_\ba_\bl _\bL_\bi_\bs_\bp _\bs_\bt_\ba_\bt_\bu_\bs
+          _\bv_\ba_\br_\bi_\ba_\bb_\bl_\be_\bs.   _\bF_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs  _\bf_\bo_\br  _\bd_\bo_\bi_\bn_\bg   _\bU_\bN_\bI_\bX-_\bs_\bp_\be_\bc_\bi_\bf_\bi_\bc
+          _\bt_\ba_\bs_\bk_\bs _\bs_\bu_\bc_\bh _\ba_\bs _\bp_\br_\bo_\bc_\be_\bs_\bs _\bc_\bo_\bn_\bt_\br_\bo_\bl.
+
+
+                    Second Movement (_\bL_\ba_\br_\bg_\bo)
+
+     7. The Reader
+          _\bA _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bo_\bf _\bt_\bh_\be  _\bs_\by_\bn_\bt_\ba_\bx  _\bc_\bo_\bd_\be_\bs  _\bu_\bs_\be_\bd  _\bb_\by  _\bt_\bh_\be
+          _\br_\be_\ba_\bd_\be_\br.  _\bA_\bn _\be_\bx_\bp_\bl_\ba_\bn_\ba_\bt_\bi_\bo_\bn _\bo_\bf _\bc_\bh_\ba_\br_\ba_\bc_\bt_\be_\br _\bm_\ba_\bc_\br_\bo_\bs.
+     8. Functions, Fclosures, and Macros
+          _\bA  _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn  _\bo_\bf  _\bv_\ba_\br_\bi_\bo_\bu_\bs  _\bt_\by_\bp_\be_\bs  _\bo_\bf  _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\ba_\bl
+          _\bo_\bb_\bj_\be_\bc_\bt_\bs.   _\bA_\bn  _\be_\bx_\ba_\bm_\bp_\bl_\be _\bo_\bf _\bt_\bh_\be _\bu_\bs_\be _\bo_\bf _\bf_\bo_\br_\be_\bi_\bg_\bn _\bf_\bu_\bn_\bc_\b-
+          _\bt_\bi_\bo_\bn_\bs.
+     9. Arrays and Vectors
+          _\bA _\bd_\be_\bt_\ba_\bi_\bl_\be_\bd _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bo_\bf _\bt_\bh_\be _\bp_\ba_\br_\bt_\bs  _\bo_\bf  _\ba_\bn  _\ba_\br_\br_\ba_\by
+          _\ba_\bn_\bd _\bo_\bf _\bM_\ba_\bc_\bl_\bi_\bs_\bp _\bc_\bo_\bm_\bp_\ba_\bt_\bi_\bb_\bl_\be _\ba_\br_\br_\ba_\by_\bs.
+     10. Exception Handling
+          _\bA _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bo_\bf _\bt_\bh_\be _\be_\br_\br_\bo_\br _\bh_\ba_\bn_\bd_\bl_\bi_\bn_\bg  _\bs_\be_\bq_\bu_\be_\bn_\bc_\be  _\ba_\bn_\bd
+          _\bo_\bf _\ba_\bu_\bt_\bo_\bl_\bo_\ba_\bd_\bi_\bn_\bg.
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9
+
+
+
+
+
+
+
+
+
+
+                    Third Movement (_\bS_\bc_\bh_\be_\br_\bz_\bo)
+
+     11. The Joseph Lister Trace Package
+          _\bA _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bo_\bf _\ba _\bv_\be_\br_\by _\bu_\bs_\be_\bf_\bu_\bl _\bd_\be_\bb_\bu_\bg_\bg_\bi_\bn_\bg _\ba_\bi_\bd.
+     12. Liszt, the lisp compiler
+          _\bA _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bo_\bf _\bt_\bh_\be _\bo_\bp_\be_\br_\ba_\bt_\bi_\bo_\bn _\bo_\bf _\bt_\bh_\be _\bc_\bo_\bm_\bp_\bi_\bl_\be_\br _\ba_\bn_\bd
+          _\bh_\bi_\bn_\bt_\bs _\bf_\bo_\br _\bm_\ba_\bk_\bi_\bn_\bg _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bc_\bo_\bm_\bp_\bi_\bl_\ba_\bb_\bl_\be.
+     13. CMU Top Level and file package
+          _\bA _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn  _\bo_\bf  _\ba  _\bt_\bo_\bp  _\bl_\be_\bv_\be_\bl  _\bw_\bi_\bt_\bh  _\ba  _\bh_\bi_\bs_\bt_\bo_\br_\by
+          _\bm_\be_\bc_\bh_\ba_\bn_\bi_\bs_\bm _\ba_\bn_\bd _\ba _\bp_\ba_\bc_\bk_\ba_\bg_\be _\bw_\bh_\bi_\bc_\bh _\bh_\be_\bl_\bp_\bs _\by_\bo_\bu _\bk_\be_\be_\bp _\bt_\br_\ba_\bc_\bk
+          _\bo_\bf _\bf_\bi_\bl_\be_\bs _\bo_\bf _\bl_\bi_\bs_\bp _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs.
+     14 Stepper
+          _\bA _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bo_\bf _\ba _\bp_\br_\bo_\bg_\br_\ba_\bm _\bw_\bh_\bi_\bc_\bh  _\bp_\be_\br_\bm_\bi_\bt_\bs  _\by_\bo_\bu  _\bt_\bo
+          _\bp_\bu_\bt  _\bb_\br_\be_\ba_\bk_\bp_\bo_\bi_\bn_\bt_\bs  _\bi_\bn  _\bl_\bi_\bs_\bp _\bc_\bo_\bd_\be _\ba_\bn_\bd _\bt_\bo _\bs_\bi_\bn_\bg_\bl_\be _\bs_\bt_\be_\bp
+          _\bi_\bt.  _\bA _\bd_\be_\bs_\bc_\br_\bi_\bp_\bt_\bi_\bo_\bn _\bo_\bf _\bt_\bh_\be _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk _\ba_\bn_\bd _\bf_\bu_\bn_\bc_\ba_\bl_\bl_\bh_\bo_\bo_\bk
+          _\bm_\be_\bc_\bh_\ba_\bn_\bi_\bs_\bm.
+     15 Fixit
+          _\bA _\bp_\br_\bo_\bg_\br_\ba_\bm _\bw_\bh_\bi_\bc_\bh _\bp_\be_\br_\bm_\bi_\bt_\bs _\by_\bo_\bu _\bt_\bo _\be_\bx_\ba_\bm_\bi_\bn_\be _\ba_\bn_\bd  _\bm_\bo_\bd_\bi_\bf_\by
+          _\be_\bv_\ba_\bl_\bu_\ba_\bt_\bi_\bo_\bn _\bs_\bt_\ba_\bc_\bk _\bi_\bn _\bo_\br_\bd_\be_\br _\bt_\bo _\bf_\bi_\bx _\bb_\bu_\bg_\bs _\bo_\bn _\bt_\bh_\be _\bf_\bl_\by.
+     16 Lisp Editor
+          _\bA _\bs_\bt_\br_\bu_\bc_\bt_\bu_\br_\be _\be_\bd_\bi_\bt_\bo_\br _\bf_\bo_\br _\bi_\bn_\bt_\be_\br_\ba_\bc_\bt_\bi_\bv_\be _\bm_\bo_\bd_\bi_\bf_\bi_\bc_\ba_\bt_\bi_\bo_\bn _\bo_\bf
+          _\bl_\bi_\bs_\bp _\bc_\bo_\bd_\be.
+
+
+                    Final Movement (_\ba_\bl_\bl_\be_\bg_\br_\bo)
+
+     Appendix A - Function Index
+     Appendix B - List of Special Symbols
+     Appendix C - Short Subjects
+          _\bG_\ba_\br_\bb_\ba_\bg_\be _\bc_\bo_\bl_\bl_\be_\bc_\bt_\bo_\br, _\bD_\be_\bb_\bu_\bg_\bg_\bi_\bn_\bg, _\bD_\be_\bf_\ba_\bu_\bl_\bt _\bT_\bo_\bp _\bL_\be_\bv_\be_\bl
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/manual/ch1.r b/usr/src/ucb/lisp/lisplib/manual/ch1.r
new file mode 100644 (file)
index 0000000..db9bd0b
--- /dev/null
@@ -0,0 +1,826 @@
+
+
+
+
+
+
+
+                         CHAPTER  1
+
+
+                         FRANZ LISP
+
+
+
+
+
+
+   1.1.  FRANZ LISP[] was  created  as  a  tool  to  further
+      research   in  symbolic  and  algebraic  manipulation,
+      artificial intelligence, and programming languages  at
+      the University of California at Berkeley.   Its  roots
+      are in a PDP-11 Lisp system which originally came from
+      Harvard.  As it grew it adopted  features  of  Maclisp
+      and  Lisp  Machine  Lisp  which enables our work to be
+      shared with colleagues at the Laboratory for  Computer
+      Science  at  M.I.T.   Substantial  compatibility  with
+      other Lisp dialects (Interlisp, UCILisp,  CMULisp)  is
+      achieved  by  means  of  support packages and compiler
+      switches.  The heart of FRANZ LISP is  written  almost
+      entirely in the programming language C.  Of course, it
+      has been greatly  extended  by  additions  written  in
+      Lisp.   A  small  part  is  written  in  the  assembly
+      language for the current host machines,  VAXen  and  a
+      couple  of  flavors  of  68000.  Because FRANZ LISP is
+      written in C, it is relatively portable  and  easy  to
+      comprehend.
+
+           FRANZ LISP is capable of running large lisp  pro-
+      grams in a timesharing environment, has facilities for
+      arrays and user defined structures, has  a  user  con-
+      trolled reader with character and word macro  capabil-
+      ities, and can interact directly with  compiled  Lisp,
+      C, Fortran, and Pascal code.
+
+           This document is a reference manual for the FRANZ
+      LISP  system.  It is not a Lisp primer or introduction
+      to the language.  Some parts will be of interest  only
+      to  those  maintaining  FRANZ  LISP  at their computer
+      site.  This document is divided into  four  Movements.
+      In  the  first  one  we  will  attempt to describe the
+      language of FRANZ LISP precisely and completely as  it
+      now  stands  (Opus  38.69,  June 1983).  In the second
+      Movement we will look at the reader,  function  types,
+____________________
+\e9   []It is rumored that this name has something to  do  with
+Franz  Liszt  [F_\brants List] (1811-1886) a Hungarian composer
+and keyboard virtuoso. These  allegations  have  never  been
+proven.
+
+
+
+\e9FRANZ LISP                                               1-1
+
+
+
+
+
+
+
+FRANZ LISP                                               1-2
+
+
+      arrays and exception handling.  In the third  Movement
+      we will look at several large support packages written
+      to help the FRANZ LISP user, namely the trace package,
+      compiler,  fixit  and  stepping  package.  Finally the
+      fourth movement contains   an  index  into  the  other
+      movements.  In the rest of this chapter we shall exam-
+      ine the data types of  FRANZ  LISP.   The  conventions
+      used  in  the  description of the FRANZ LISP functions
+      will be given in 1.3 --  it  is  very  important  that
+      these conventions are  understood.
+
+
+
+   1.2.  Data Types   FRANZ LISP has  fourteen  data  types.
+      In  this  section we shall look in detail at each type
+      and if a type is divisible we shall  look  inside  it.
+      There  is  a  Lisp function _\bt_\by_\bp_\be which will return the
+      type name of a lisp  object.   This  is  the  official
+      FRANZ  LISP  name  for  that type and we will use this
+      name and this name only in the manual to avoid confus-
+      ing  the  reader.   The  types  are listed in terms of
+      importance rather than alphabetically.
+
+
+
+      1.2.0.  lispval   This is the name we use to  describe
+         any  lisp  object.   The  function  _\bt_\by_\bp_\be will never
+         return `lispval'.
+
+
+
+      1.2.1.  symbol   This object corresponds to a variable
+         in most other programming languages.  It may have a
+         value or may be `unbound'.  A symbol may be  _\bl_\ba_\bm_\bb_\bd_\ba
+         _\bb_\bo_\bu_\bn_\bd meaning that its current value is stored away
+         somewhere and the symbol  is given a new value  for
+         the  duration  of a certain context.  When the Lisp
+         processor   leaves  that  context,   the   symbol's
+         current  value  is thrown away and its old value is
+         restored.
+\e9         A symbol may also have a  _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn  _\bb_\bi_\bn_\bd_\bi_\bn_\bg.   This
+         function  binding  is  static;  it cannot be lambda
+         bound.  Whenever the symbol is used  in  the  func-
+         tional  position  of a Lisp expression the function
+         binding of the symbol is examined  (see  Chapter  4
+         for more details on  evaluation).
+\e9         A symbol may also have  a  _\bp_\br_\bo_\bp_\be_\br_\bt_\by  _\bl_\bi_\bs_\bt,  another
+         static  data structure.  The property list consists
+         of a list of an even number of elements, considered
+         to  be  grouped  as pairs. The first element of the
+         pair is the _\bi_\bn_\bd_\bi_\bc_\ba_\bt_\bo_\br the second the _\bv_\ba_\bl_\bu_\be of  that
+         indicator.
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+FRANZ LISP                                               1-3
+
+
+         Each symbol has a print name (_\bp_\bn_\ba_\bm_\be) which  is  how
+         this  symbol is accessed from input and referred to
+         on  (printed) output.
+\e9         A symbol also has a hashlink used to  link  symbols
+         together  in the oblist -- this field is inaccessi-
+         ble to the lisp user.
+\e9         Symbols are created by the reader and by the  func-
+         tions  _\bc_\bo_\bn_\bc_\ba_\bt,  _\bm_\ba_\bk_\bn_\ba_\bm and their derivatives.  Most
+         symbols live  on  FRANZ  LISP's  sole  _\bo_\bb_\bl_\bi_\bs_\bt,  and
+         therefore  two symbols with the same print name are
+         usually the  exact same object (they are _\be_\bq).  Sym-
+         bols  which  are  not  on the oblist are said to be
+         _\bu_\bn_\bi_\bn_\bt_\be_\br_\bn_\be_\bd.  The function _\bm_\ba_\bk_\bn_\ba_\bm creates uninterned
+         symbols while _\bc_\bo_\bn_\bc_\ba_\bt creates _\bi_\bn_\bt_\be_\br_\bn_\be_\bd ones.
+
+
+\e8    ____________________________________________________________
+     Subpart name   Get value   Set value          Type
+
+\e8    ____________________________________________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b____________________________________________________________
+        value         eval         set            lispval
+                                  setq
+\e8    ____________________________________________________________
+       property       plist     setplist        list or nil
+         list          get       putprop
+                                 defprop
+\e8    ____________________________________________________________
+       function       getd        putd      array, binary, list
+       binding                     def            or nil
+\e8    ____________________________________________________________
+      print name    get_pname                     string
+\e8    ____________________________________________________________
+      hash link
+\e8    ____________________________________________________________
+\e7   |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+                 |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+                             |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+                                         |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+                                                               |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+      1.2.2.  list   A list cell has two parts,  called  the
+         car  and  cdr.  List cells are created by the func-
+         tion _\bc_\bo_\bn_\bs.
+
+
+\e8          ________________________________________________
+           Subpart name   Get value   Set value    Type
+
+\e8          ________________________________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b________________________________________________
+               car           car       rplaca     lispval
+\e8          ________________________________________________
+               cdr           cdr       rplacd     lispval
+\e8          ________________________________________________
+\e7         |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+\e9                       |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+\e9                                   |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+\e9                                               |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+\e9                                                         |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+\e9
+
+
+
+
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+FRANZ LISP                                               1-4
+
+
+      1.2.3.  binary   This type acts as a  function  header
+         for  machine  coded functions.  It has two parts, a
+         pointer to the start of the function and  a  symbol
+         whose print name describes the argument _\bd_\bi_\bs_\bc_\bi_\bp_\bl_\bi_\bn_\be.
+         The discipline (if _\bl_\ba_\bm_\bb_\bd_\ba, _\bm_\ba_\bc_\br_\bo or _\bn_\bl_\ba_\bm_\bb_\bd_\ba) deter-
+         mines  whether  the arguments to this function will
+         be evaluated by the caller before this function  is
+         called.   If  the  discipline is a string (specifi-
+         cally "_\bs_\bu_\bb_\br_\bo_\bu_\bt_\bi_\bn_\be", "_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn", "_\bi_\bn_\bt_\be_\bg_\be_\br-_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn",
+         "_\br_\be_\ba_\bl-_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn", "_\bc-_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn", "_\bd_\bo_\bu_\bb_\bl_\be-_\bc-_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn",
+         or "_\bv_\be_\bc_\bt_\bo_\br-_\bc-_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn" ) then this  function  is  a
+         foreign  subroutine  or  function (see 8.5 for more
+         details on this).  Although the type of  the  _\be_\bn_\bt_\br_\by
+         field  of a binary type object is usually string or
+         other, the object pointed to is actually a sequence
+         of machine instructions.
+         Objects of type binary are  created  by  _\bm_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn,
+         _\bc_\bf_\ba_\bs_\bl, and _\bg_\be_\bt_\ba_\bd_\bd_\br_\be_\bs_\bs.
+
+
+\e8      _________________________________________________________
+       Subpart name   Get value   Set value         Type
+
+\e8      _________________________________________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b_________________________________________________________
+          entry       getentry                string or fixnum
+\e8      _________________________________________________________
+        discipline     getdisc     putdisc    symbol or fixnum
+\e8      _________________________________________________________
+\e7     |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+\e9                   |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+\e9                               |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+\e9                                           |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+\e9                                                              |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+\e9
+
+
+      1.2.4.  fixnum   A fixnum is an  integer  constant  in
+         the  range -2[31] to 2[31]-1.  Small fixnums (-1024
+         to 1023) are stored in  a  special  table  so  they
+         needn't be allocated each time one is needed.
+
+
+
+      1.2.5.  flonum   A flonum is a double  precision  real
+         number  in  the  range +\b_2.9x10[-37] to +\b_1.7x10[38].
+         There are approximately sixteen decimal  digits  of
+         precision.
+
+
+
+      1.2.6.  bignum   A bignum is an integer of potentially
+         unbounded  size.   When  integer arithmetic exceeds
+         the limits of fixnums mentioned above, the calcula-
+         tion  is  automatically  done with bignums.  Should
+         calculation with bignums give a result which can be
+         represented  as a fixnum, then the fixnum represen-
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+FRANZ LISP                                               1-5
+
+
+         tation will be used[].  This contraction  is  known
+         as  _\bi_\bn_\bt_\be_\bg_\be_\br  _\bn_\bo_\br_\bm_\ba_\bl_\bi_\bz_\ba_\bt_\bi_\bo_\bn.   Many  Lisp  functions
+         assume that integers are normalized.   Bignums  are
+         composed  of  a  sequence  of list cells and a cell
+         known as an sdot.  The user should consider a  big-
+         num structure indivisible and use functions such as
+         _\bh_\ba_\bi_\bp_\ba_\br_\bt, and _\bb_\bi_\bg_\bn_\bu_\bm-_\bl_\be_\bf_\bt_\bs_\bh_\bi_\bf_\bt to extract  parts  of
+         it.
+
+
+
+      1.2.7.   string    A  string  is  a  null   terminated
+         sequence  of characters.  Most functions of symbols
+         which operate on the symbol's print name will  also
+         work  on strings.  The default reader syntax is set
+         so that a sequence of characters surrounded by dou-
+         ble quotes is a string.
+
+
+
+      1.2.8.  port   A port is a structure which the  system
+         I/O routines can reference to transfer data between
+         the Lisp system and external media.   Unlike  other
+         Lisp  objects  there  are  a very limited number of
+         ports (20).  Ports are allocated by _\bi_\bn_\bf_\bi_\bl_\be and _\bo_\bu_\bt_\b-
+         _\bf_\bi_\bl_\be  and  deallocated  by  _\bc_\bl_\bo_\bs_\be and _\br_\be_\bs_\be_\bt_\bi_\bo.  The
+         _\bp_\br_\bi_\bn_\bt function prints a port as a percent sign fol-
+         lowed  by  the  name of the file it is connected to
+         (if the port was opened  by  _\bf_\bi_\bl_\be_\bo_\bp_\be_\bn,  _\bi_\bn_\bf_\bi_\bl_\be,  _\bo_\br
+         _\bo_\bu_\bt_\bf_\bi_\bl_\be).   During initialization, FRANZ LISP binds
+         the symbol piport to a port attached to  the  stan-
+         dard  input  stream.   This port prints as %$stdin.
+         There are ports connected to  the  standard  output
+         and  error  streams,  which  print  as %$stdout and
+         %$stderr.  This is discussed in more detail at  the
+         beginning of Chapter 5.
+
+
+
+      1.2.9.  vector    Vectors  are  indexed  sequences  of
+         data.   They  can  be used to implement a notion of
+         user-defined types, via their  associated  property
+         list.    They  make  hunks  (see  below)  logically
+         unnecessary, although hunks  are  very  efficiently
+         garbage  collected.  There is a second kind of vec-
+         tor,  called  an  immediate-vector,  which   stores
+         binary  data.   The  name  that  the  function _\bt_\by_\bp_\be
+____________________
+\e9   []The current algorithms for  integer  arithmetic  opera-
+tions will return (in certain cases) a result between +\b_2[30]
+and 2[31] as a bignum although this could be represented  as
+a fixnum.
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+FRANZ LISP                                               1-6
+
+
+         returns   for   immediate-vectors    is    vectori.
+         Immediate-vectors   could   be  used  to  implement
+         strings and block-flonum arrays, for example.  Vec-
+         tors  are  discussed  in  chapter 9.  The functions
+         _\bn_\be_\bw-_\bv_\be_\bc_\bt_\bo_\br, and _\bv_\be_\bc_\bt_\bo_\br, can be used to create  vec-
+         tors.
+
+
+\e8          ________________________________________________
+           Subpart name   Get value   Set value    Type
+
+\e8          ________________________________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b________________________________________________
+             datum[_\bi]       vref        vset      lispval
+\e8          ________________________________________________
+             property       vprop     vsetprop    lispval
+                                      vputprop
+\e8          ________________________________________________
+               size         vsize         -       fixnum
+\e8          ________________________________________________
+\e7         |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+                       |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+                                   |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+                                               |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+                                                         |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+      1.2.10.  array   Arrays are rather  complicated  types
+         and  are  fully  described  in Chapter 9.  An array
+         consists of a block of contiguous data, a  function
+         to access that data and auxiliary fields for use by
+         the accessing function.  Since an array's accessing
+         function  is created by the user, an array can have
+         any form the user chooses (e.g. n-dimensional, tri-
+         angular, or hash table).
+         Arrays are created by the function _\bm_\ba_\br_\br_\ba_\by.
+
+
+\e8   _______________________________________________________________
+     Subpart name     Get value   Set value          Type
+
+\e8   _______________________________________________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b_______________________________________________________________
+    access function   getaccess   putaccess      binary, list
+                                                   or symbol
+\e8   _______________________________________________________________
+       auxiliary       getaux      putaux           lispval
+\e8   _______________________________________________________________
+         data         arrayref     replace    block of contiguous
+                                     set            lispval
+\e8   _______________________________________________________________
+        length        getlength   putlength         fixnum
+\e8   _______________________________________________________________
+         delta        getdelta    putdelta          fixnum
+\e8   _______________________________________________________________
+\e7  |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+                   |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+                               |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+                                           |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+                                                                 |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+      1.2.11.  value   A value cell contains a pointer to  a
+         lispval.   This  type  is  used mainly by arrays of
+         general lisp objects.  Value cells are created with
+         the  _\bp_\bt_\br  function.   A  value  cell  containing  a
+         pointer  to  the  symbol  `foo'   is   printed   as
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+FRANZ LISP                                               1-7
+
+
+         `(ptr to)foo'
+
+
+
+      1.2.12.  hunk   A hunk is a vector of from  1  to  128
+         lispvals.   Once  a  hunk  is  created  (by _\bh_\bu_\bn_\bk or
+         _\bm_\ba_\bk_\bh_\bu_\bn_\bk) it cannot grow or shrink.  The access time
+         for an element of a hunk is slower than a list cell
+         element but faster than an array.  Hunks are really
+         only  allocated  in  sizes which are powers of two,
+         but can appear to the user to be any size in the  1
+         to  128  range.   Users  of hunks must realize that
+         (_\bn_\bo_\bt (_\ba_\bt_\bo_\bm '_\bl_\bi_\bs_\bp_\bv_\ba_\bl)) will return true  if  _\bl_\bi_\bs_\bp_\bv_\ba_\bl
+         is  a hunk.  Most lisp systems do not have a direct
+         test for a list cell and instead use the above test
+         and  assume  that  a true result means _\bl_\bi_\bs_\bp_\bv_\ba_\bl is a
+         list cell.  In FRANZ LISP you can use _\bd_\bt_\bp_\br to check
+         for  a  list  cell.   Although  hunks  are not list
+         cells, you can still access the first two hunk ele-
+         ments  with _\bc_\bd_\br and _\bc_\ba_\br and you can access any hunk
+         element with _\bc_\bx_\br[].  You can set the value  of  the
+         first two elements of a hunk with _\br_\bp_\bl_\ba_\bc_\bd and _\br_\bp_\bl_\ba_\bc_\ba
+         and you can set the value of  any  element  of  the
+         hunk  with  _\br_\bp_\bl_\ba_\bc_\bx.   A hunk is printed by printing
+         its contents surrounded by { and }.  However a hunk
+         cannot  be read in in this way in the standard lisp
+         system.  It is easy to write a reader macro  to  do
+         this if desired.
+
+
+
+      1.2.13.   other    Occasionally,  you  can  obtain   a
+         pointer  to  storage not allocated by the lisp sys-
+         tem.  One example of this is  the  entry  field  of
+         those  FRANZ  LISP  functions  written  in C.  Such
+         objects are classified as of type  other.   Foreign
+         functions  which  call malloc to allocate their own
+         space, may also inadvertantly create such  objects.
+         The  garbage  collector  is supposed to ignore such
+         objects.
+
+
+
+   1.3.  Documentation   The conventions used in the follow-
+      ing  chapters  were  designed  to give a great deal of
+      information in a brief space.  The  first  line  of  a
+      function  description  contains  the  function name in
+      bold face and then lists the arguments, if  any.   The
+____________________
+\e9   []In a hunk, the function _\bc_\bd_\br references the  first  ele-
+ment and _\bc_\ba_\br the second.
+
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+FRANZ LISP                                               1-8
+
+
+      arguments all have names which begin with a letter  or
+      letters  and  an  underscore.  The letter(s) gives the
+      allowable type(s) for that argument according to  this
+      table.
+
+
+\e8     _______________________________________________________
+      Letter                Allowable type(s)
+
+\e8     _______________________________________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b_______________________________________________________
+      g        any type
+\e8     _______________________________________________________
+      s        symbol (although nil may not be allowed)
+\e8     _______________________________________________________
+      t        string
+\e8     _______________________________________________________
+      l        list (although nil may be allowed)
+\e8     _______________________________________________________
+      n        number (fixnum, flonum, bignum)
+\e8     _______________________________________________________
+      i        integer (fixnum, bignum)
+\e8     _______________________________________________________
+      x        fixnum
+\e8     _______________________________________________________
+      b        bignum
+\e8     _______________________________________________________
+      f        flonum
+\e8     _______________________________________________________
+      u        function type (either binary or lambda body)
+\e8     _______________________________________________________
+      y        binary
+\e8     _______________________________________________________
+      v        vector
+\e8     _______________________________________________________
+      V        vectori
+\e8     _______________________________________________________
+      a        array
+\e8     _______________________________________________________
+      e        value
+\e8     _______________________________________________________
+      p        port (or nil)
+\e8     _______________________________________________________
+      h        hunk
+\e8     _______________________________________________________
+\e7    |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+            |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+                                                           |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+      In the first line of  a  function  description,  those
+      arguments preceded by a quote mark are evaluated (usu-
+      ally before the function is called).  The quoting con-
+      vention  is  used  so  that  we can give a name to the
+      result of evaluating the argument and we can  describe
+      the  allowable types.  If an argument is not quoted it
+      does  not  mean  that  that  argument  will   not   be
+      evaluated,  but  rather  that  if it is evaluated, the
+      time at which it is  evaluated  will  be  specifically
+      mentioned in the function description.  Optional argu-
+      ments are surrounded by square brackets.  An  ellipsis
+      (...) means zero or more occurrences of an argument of
+      the directly preceding type.
+
+
+
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/manual/ch11.r b/usr/src/ucb/lisp/lisplib/manual/ch11.r
new file mode 100644 (file)
index 0000000..bc85282
--- /dev/null
@@ -0,0 +1,328 @@
+
+
+
+
+
+
+
+                        CHAPTER  11
+
+
+              The Joseph Lister Trace Package
+
+
+
+
+     The Joseph Lister[] Trace package is an important  tool
+for the interactive debugging of a Lisp program.  It  allows
+you  to  examine selected  calls to a function or functions,
+and optionally to stop execution  of  the  Lisp  program  to
+examine the values of variables.
+
+     The trace package is a set of Lisp programs located  in
+the    Lisp   program   library   (usually   in   the   file
+/usr/lib/lisp/trace.l).  Although not normally loaded in the
+Lisp  system,  the  package will be loaded in when the first
+call to _\bt_\br_\ba_\bc_\be is made.
+
+(trace [ls_arg1 ...])
+
+     WHERE:   the form of the ls_arg_\bi is described below.
+
+     RETURNS: a list of the  function  sucessfully  modified
+              for  tracing.   If  no  arguments are given to
+              _\bt_\br_\ba_\bc_\be, a list of all functions currently being
+              traced is returned.
+
+     SIDE EFFECT: The function definitions of the  functions
+                  to trace are modified.
+
+
+The ls_arg_\bi can have one of the following forms:
+
+
+  foo - when foo is entered and exited, the  trace  informa-
+       tion will be printed.
+
+
+  (foo break) - when foo is entered  and  exited  the  trace
+       information  will  be  printed.  Also, just after the
+       trace information for foo is printed upon entry,  you
+       will  be put in  a special break loop.  The prompt is
+       `T>' and you may type any Lisp  expression,  and  see
+       its  value printed.  The _\bith argument to the function
+       just called can be accessed as (arg _\bi).  To leave the
+       trace   loop,  just  type  ^D  or  (tracereturn)  and
+____________________
+\e9   []_\bL_\bi_\bs_\bt_\be_\br, _\bJ_\bo_\bs_\be_\bp_\bh     1st  Baron  Lister  of  Lyme  Regis,
+1827-1912; English surgeon: introduced antiseptic surgery.
+
+
+
+\e9The Joseph Lister Trace Package                         11-1
+
+
+
+
+
+
+
+The Joseph Lister Trace Package                         11-2
+
+
+       execution will continue.  Note that ^D will work only
+       on UNIX systems.
+
+
+  (foo if expression) - when foo is entered and the  expres-
+       sion evaluates to non-nil, then the trace information
+       will be printed for both exit and entry.  If  expres-
+       sion evaluates to nil, then no trace information will
+       be printed.
+
+
+  (foo ifnot expression) -  when  foo  is  entered  and  the
+       expression  evaluates to nil, then the trace informa-
+       tion will be printed for both  entry  and  exit.   If
+       both  if and ifnot are specified, then the if expres-
+       sion must evaluate to non nil AND the  ifnot  expres-
+       sion  must  evaluate to nil for the trace information
+       to be printed out.
+
+
+  (foo evalin expression) - when foo is  entered  and  after
+       the  entry  trace  information is printed, expression
+       will be evaluated. Exit  trace  information  will  be
+       printed when foo exits.
+
+
+  (foo evalout expression) -  when  foo  is  entered,  entry
+       trace  information  will be printed.  When foo exits,
+       and before the exit  trace  information  is  printed,
+       expression will be evaluated.
+
+
+  (foo evalinout expression) - this has the same  effect  as
+       (trace (foo evalin expression evalout expression)).
+
+
+  (foo lprint) - this tells _\bt_\br_\ba_\bc_\be to use the  level  printer
+       when  printing  the arguments to and the result of  a
+       call to foo.  The level printer prints only  the  top
+       levels  of  list structure. Any structure below three
+       levels is printed as a &.  This allows you  to  trace
+       functions with massive arguments or results.
+
+
+
+          The following trace options  permit  one  to  have
+     greater control over each action which takes place when
+     a function is traced.  These options are only meant  to
+     be used by people who need special hooks into the trace
+     package.  Most people should skip reading this section.
+
+
+  (foo traceenter  tefunc)  -  this  tells  _\bt_\br_\ba_\bc_\be  that  the
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+The Joseph Lister Trace Package                         11-3
+
+
+       function  to be called when foo is entered is tefunc.
+       tefunc should be a lambda of two arguments, the first
+       argument  will  be  bound to the name of the function
+       being traced, foo in this case.  The second  argument
+       will  be  bound to the list of arguments to which foo
+       should be applied.  The function tefunc should  print
+       some  sort  of "entering foo" message.  It should not
+       apply foo to the arguments,  however.  That  is  done
+       later on.
+
+
+  (foo traceexit txfunc) - this tells _\bt_\br_\ba_\bc_\be that  the  func-
+       tion  to  be  called  when  foo  is exited is txfunc.
+       txfunc should be a lambda of two arguments, the first
+       argument  will  be  bound to the name of the function
+       being traced, foo in this case.  The second  argument
+       will  be bound to the result of the call to foo.  The
+       function txfunc should print some  sort  of  "exiting
+       foo" message.
+
+
+  (foo evfcn evfunc) - this tells _\bt_\br_\ba_\bc_\be that the form evfunc
+       should  be  evaluated to get the value of foo applied
+       to its arguments. This option is a bit different from
+       the  other  special options since evfunc will usually
+       be an expression, not just the name  of  a  function,
+       and  that  expression will be specific to the evalua-
+       tion of  function  foo.   The  argument  list  to  be
+       applied will be available as T-arglist.
+
+
+  (foo printargs prfunc) - this tells _\bt_\br_\ba_\bc_\be to  used  prfunc
+       to print the arguments  to be applied to the function
+       foo.  prfunc should be a lambda of one argument.  You
+       might  want  to use this option if you wanted a print
+       function which could  handle  circular  lists.   This
+       option  will work only if you do not specify your own
+       traceenter function.  Specifying the option lprint is
+       just  a simple way of changing the printargs function
+       to the level printer.
+
+
+  (foo printres prfunc) - this tells _\bt_\br_\ba_\bc_\be to use prfunc  to
+       print the result of evaluating foo.  prfunc should be
+       a lambda of one argument.  This option will work only
+       if  you  do  not specify your own traceexit function.
+       Specifying the option lprint changes printres to  the
+       level printer.
+
+
+
+          You may specify more  than  one  option  for  each
+     function traced. For example:
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+The Joseph Lister Trace Package                         11-4
+
+
+     (_\bt_\br_\ba_\bc_\be (_\bf_\bo_\bo _\bi_\bf (_\be_\bq _\b3 (_\ba_\br_\bg _\b1)) _\bb_\br_\be_\ba_\bk _\bl_\bp_\br_\bi_\bn_\bt) (_\bb_\ba_\br _\be_\bv_\ba_\bl_\bi_\bn
+     (_\bp_\br_\bi_\bn_\bt _\bx_\by_\bz_\bz_\by)))
+
+     This tells _\bt_\br_\ba_\bc_\be to trace two more functions,  foo  and
+     bar.   Should  foo be called with the first argument _\be_\bq
+     to 3, then the entering foo  message  will  be  printed
+     with  the  level  printer.   Next it will enter a trace
+     break loop, allowing you to evaluate any  lisp  expres-
+     sions.  When you exit the trace break loop, foo will be
+     applied to its arguments and the resulting  value  will
+     be printed, again using the level printer.  Bar is also
+     traced, and each time bar is entered, an  entering  bar
+     message  will  be  printed  and then the value of xyzzy
+     will be printed.  Next bar will be applied to its argu-
+     ments  and  the  result  will  be printed.  If you tell
+     _\bt_\br_\ba_\bc_\be to trace a function which is already  traced,  it
+     will  first  _\bu_\bn_\bt_\br_\ba_\bc_\be  it.   Thus if you want to specify
+     more than one trace option for a function, you must  do
+     it all at once.  The following is _\bn_\bo_\bt equivalent to the
+     preceding call to _\bt_\br_\ba_\bc_\be for foo:
+
+     (_\bt_\br_\ba_\bc_\be (_\bf_\bo_\bo  _\bi_\bf  (_\be_\bq  _\b3  (_\ba_\br_\bg  _\b1)))  (_\bf_\bo_\bo  _\bb_\br_\be_\ba_\bk)  (_\bf_\bo_\bo
+     _\bl_\bp_\br_\bi_\bn_\bt))
+
+     In this example, only the last option, lprint, will  be
+     in effect.
+
+          If the symbol $tracemute is given a non nil value,
+     printing  of  the  function name and arguments on entry
+     and exit will be surpressed.  This is particularly use-
+     ful  if  the  function you are tracing fails after many
+     calls to it.  In this case  you  would  tell  _\bt_\br_\ba_\bc_\be  to
+     trace  the function, set $tracemute to t, and begin the
+     computation.  When an error occurs  you  can  use  _\bt_\br_\ba_\b-
+     _\bc_\be_\bd_\bu_\bm_\bp to print out the current trace frames.
+
+          Generally the trace package has its  own  internal
+     names  for  the the lisp functions it uses, so that you
+     can feel free to trace system functions like  _\bc_\bo_\bn_\bd  and
+     not worry about adverse interaction with the actions of
+     the trace package.  You can trace any type of function:
+     lambda,  nlambda,  lexpr  or  macro whether compiled or
+     interpreted and you can  even  trace  array  references
+     (however  you  should  not attempt to store in an array
+     which has been traced).
+
+          When tracing compiled code keep in mind that  many
+     function  calls  are  translated  directly  to  machine
+     language  or other equivalent  function calls.  A  full
+     list of open coded functions is listed at the beginning
+     of  the  liszt  compiler  source.   _\bT_\br_\ba_\bc_\be  will  do   a
+     (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bt_\br_\ba_\bn_\bs_\bl_\bi_\bn_\bk _\bn_\bi_\bl)  to  insure that the new traced
+     definitions it defines are called instead  of  the  old
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+The Joseph Lister Trace Package                         11-5
+
+
+     untraced  ones.  You may notice that compiled code will
+     run slower after this is done.
+
+(traceargs s_func [x_level])
+
+     WHERE:   if x_level is missing it is assumed to be 1.
+
+     RETURNS: the arguments to the x_level_\bt_\bh call to  traced
+              function s_func are returned.
+
+(tracedump)
+
+     SIDE EFFECT: the  currently  active  trace  frames  are
+                  printed  on  the terminal.  returns a list
+                  of functions untraced.
+
+(untrace [s_arg1 ...])
+
+     RETURNS: a list of the functions which were untraced.
+
+     NOTE: if no arguments  are  given,  all  functions  are
+           untraced.
+
+     SIDE EFFECT: the old function definitions of all traced
+                  functions  are restored except in the case
+                  where it appears that the current  defini-
+                  tion  of  a  function  was  not created by
+                  trace.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/manual/ch12.r b/usr/src/ucb/lisp/lisplib/manual/ch12.r
new file mode 100644 (file)
index 0000000..5f24238
--- /dev/null
@@ -0,0 +1,786 @@
+
+
+
+
+
+
+
+                        CHAPTER  12
+
+
+                 Liszt - the lisp compiler
+
+
+
+
+
+
+   12.1.  General strategy of the compiler
+
+           The purpose of the lisp compiler,  Liszt,  is  to
+      create  an  object  module which when brought into the
+      lisp system using _\bf_\ba_\bs_\bl will have the  same  effect  as
+      bringing in the corresponding lisp coded source module
+      with _\bl_\bo_\ba_\bd with one important exception, functions will
+      be  defined  as sequences of machine language instruc-
+      tions, instead of lisp S-expressions.  Liszt is not  a
+      function compiler, it is a _\bf_\bi_\bl_\be compiler.  Such a file
+      can contain more than  function  definitions;  it  can
+      contain  other  lisp S-expressions which are evaluated
+      at load time.  These other S-expressions will also  be
+      stored in the object module produced by Liszt and will
+      be evaluated at fasl time.
+
+           As is almost universally true of Lisp  compilers,
+      the  main  pass of Liszt is written in Lisp.  A subse-
+      quent pass is the assembler,  for  which  we  use  the
+      standard UNIX assembler.
+
+
+
+   12.2.  Running the compiler
+
+           The compiler is normally run in this manner:
+      % liszt foo
+      will compile the file foo.l or foo (the preferred  way
+      to indicate a lisp source file is to end the file name
+      with `.l').  The result of  the  compilation  will  be
+      placed  in  the  file  foo.o   if no fatal errors were
+      detected.  All messages which Liszt  generates  go  to
+      the  standard  output.  Normally each function name is
+      printed  before  it  is  compiled   (the   -q   option
+      suppresses this).
+
+
+
+   12.3.  Special forms
+
+           Liszt makes one pass over  the  source  file.  It
+      processes each form in this way:
+\e9
+
+\e9Liszt - the lisp compiler                               12-1
+
+
+
+
+
+
+
+Liszt - the lisp compiler                               12-2
+
+
+      12.3.1.  macro expansion
+
+              If the form is a macro invocation (i.e it is a
+         list  whose  car is a symbol whose function binding
+         is  a  macro),  then  that  macro   invocation   is
+         expanded.   This  is  repeated  until the top level
+         form is not a macro invocation.  When Liszt begins,
+         there are already some macros defined, in fact some
+         functions (such as defun) are actually macros.  The
+         user  may  define  his  own  macros as well.  For a
+         macro to be used it must be  defined  in  the  Lisp
+         system in which Liszt runs.
+
+
+
+      12.3.2.  classification
+
+              After all macro expansion is done, the form is
+         classified according to its _\bc_\ba_\br (if the form is not
+         a list, then it is classified as an _\bo_\bt_\bh_\be_\br).
+
+
+
+         12.3.2.1.  eval-when
+
+                 The   form   of   eval-when    is    (_\be_\bv_\ba_\bl-
+            _\bw_\bh_\be_\bn (_\bt_\bi_\bm_\be_\b1 _\bt_\bi_\bm_\be_\b2 ...) _\bf_\bo_\br_\bm_\b1 _\bf_\bo_\br_\bm_\b2 ...)    where
+            the time_\bi are one of  _\be_\bv_\ba_\bl,  _\bc_\bo_\bm_\bp_\bi_\bl_\be,  or  _\bl_\bo_\ba_\bd.
+            The  compiler examines the form_\bi in sequence and
+            the action taken depends on what is in the  time
+            list.   If  _\bc_\bo_\bm_\bp_\bi_\bl_\be is in the list then the com-
+            piler will invoke _\be_\bv_\ba_\bl on each form_\bi as it exam-
+            ines  it.   If _\bl_\bo_\ba_\bd is in the list then the com-
+            pile will recursively  call  itself  to  compile
+            each form_\bi as it examines it.  Note that if _\bc_\bo_\bm_\b-
+            _\bp_\bi_\bl_\be and _\bl_\bo_\ba_\bd are in the  time  list,  then  the
+            compiler  will  both  evaluate  and compile each
+            form.  This is useful if you need a function  to
+            be  defined in the compiler at both compile time
+            (perhaps to aid macro expansion) and at run time
+            (after the file is _\bf_\ba_\bs_\bled in).
+
+
+
+         12.3.2.2.  declare
+
+                 Declare  is  used  to  provide  information
+            about  functions  and variables to the compiler.
+            It   is   (almost)    equivalent    to    (_\be_\bv_\ba_\bl-
+            _\bw_\bh_\be_\bn (_\bc_\bo_\bm_\bp_\bi_\bl_\be) ...).   You may declare functions
+            to  be  one  of  three  types:  lambda  (*expr),
+            nlambda  (*fexpr), lexpr (*lexpr).  The names in
+            parenthesis  are  the  Maclisp  names  and   are
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                               12-3
+
+
+            accepted  by  the compiler as well (and not just
+            when the compiler is in  Maclisp  mode).   Func-
+            tions  are  assumed to be lambdas until they are
+            declared otherwise or are  defined  differently.
+            The  compiler treats calls to lambdas and lexprs
+            equivalently, so you needn't worry about declar-
+            ing  lexprs  either.  It is important to declare
+            nlambdas or define  them  before  calling  them.
+            Another attribute you can declare for a function
+            is localf which makes the function  `local'.   A
+            local function's name is known only to the func-
+            tions  defined  within  the  file  itself.   The
+            advantage  of a local function is that is can be
+            entered and exited very quickly and it can  have
+            the  same name as a function in another file and
+            there will be no name conflict.
+
+                 Variables may be declared special or unspe-
+            cial.   When  a special variable is lambda bound
+            (either in a lambda, prog or do expression), its
+            old  value  is  stored  away  on a stack for the
+            duration of the lambda, prog or  do  expression.
+            This  takes  time  and  is  often not necessary.
+            Therefore the default classification  for  vari-
+            ables  is  unspecial.  Space for unspecial vari-
+            ables is dynamically allocated on a  stack.   An
+            unspecial  variable  can  only  be accessed from
+            within the function where it is created  by  its
+            presence  in  a  lambda,  prog  or do expression
+            variable list.  It is possible to  declare  that
+            all  variables  are  special  as  will  be shown
+            below.
+
+                 You may declare any  number  of  things  in
+            each declare statement.  A sample declaration is
+            (_\bd_\be_\bc_\bl_\ba_\br_\be
+                 (_\bl_\ba_\bm_\bb_\bd_\ba _\bf_\bu_\bn_\bc_\b1 _\bf_\bu_\bn_\bc_\b2)
+                 (*_\bf_\be_\bx_\bp_\br _\bf_\bu_\bn_\bc_\b3)
+                 (*_\bl_\be_\bx_\bp_\br _\bf_\bu_\bn_\bc_\b4)
+                 (_\bl_\bo_\bc_\ba_\bl_\bf _\bf_\bu_\bn_\bc_\b5)
+                 (_\bs_\bp_\be_\bc_\bi_\ba_\bl _\bv_\ba_\br_\b1 _\bv_\ba_\br_\b2 _\bv_\ba_\br_\b3)
+                 (_\bu_\bn_\bs_\bp_\be_\bc_\bi_\ba_\bl _\bv_\ba_\br_\b4))
+
+                 You may also declare all  variables  to  be
+            special  with  (_\bd_\be_\bc_\bl_\ba_\br_\be (_\bs_\bp_\be_\bc_\bi_\ba_\bl_\bs _\bt)).   You may
+            declare that macro definitions  should  be  com-
+            piled  as  well  as evaluated at compile time by
+            (_\bd_\be_\bc_\bl_\ba_\br_\be (_\bm_\ba_\bc_\br_\bo_\bs _\bt)).  In fact, as was mentioned
+            above,    declare    is    much    like   (_\be_\bv_\ba_\bl-
+            _\bw_\bh_\be_\bn (_\bc_\bo_\bm_\bp_\bi_\bl_\be) ...).  Thus if the compiler  sees
+            (_\bd_\be_\bc_\bl_\ba_\br_\be (_\bf_\bo_\bo _\bb_\ba_\br))  and foo is defined, then it
+            will evaluate (_\bf_\bo_\bo _\bb_\ba_\br).  If foo is not  defined
+            then an undefined declare attribute warning will
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                               12-4
+
+
+            be issued.
+
+
+
+         12.3.2.3.  (progn 'compile form1 form2 ... formn)
+
+                 When the compiler sees this it simply  com-
+            piles  form1  through  formn as if they too were
+            seen at top level.  One use for this is to allow
+            a  macro  at  top-level to expand into more than
+            one function definition for the compiler to com-
+            pile.
+
+
+
+         12.3.2.4.  include/includef
+
+                 _\bI_\bn_\bc_\bl_\bu_\bd_\be and _\bi_\bn_\bc_\bl_\bu_\bd_\be_\bf cause another file  to
+            be  read  and  compiled  by  the  compiler.  The
+            result is the same as if the included file  were
+            textually  inserted into the original file.  The
+            only difference between _\bi_\bn_\bc_\bl_\bu_\bd_\be and _\bi_\bn_\bc_\bl_\bu_\bd_\be_\bf  is
+            that  include  doesn't evaluate its argument and
+            includef does.  Nested includes are allowed.
+
+
+
+         12.3.2.5.  def
+
+                 A def form is used to  define  a  function.
+            The  macros  _\bd_\be_\bf_\bu_\bn  and _\bd_\be_\bf_\bm_\ba_\bc_\br_\bo expand to a def
+            form.   If  the  function  being  defined  is  a
+            lambda,  nlambda or lexpr then the compiler con-
+            verts the  lisp  definition  to  a  sequence  of
+            machine  language instructions.  If the function
+            being defined is a macro, then the compiler will
+            evaluate the definition, thus defining the macro
+            withing the running Lisp compiler.  Furthermore,
+            if  the  variable  _\bm_\ba_\bc_\br_\bo_\bs  is  set  to a non nil
+            value, then the macro definition  will  also  be
+            translated  to machine language and thus will be
+            defined when the object file is fasled in.   The
+            variable    _\bm_\ba_\bc_\br_\bo_\bs    is    set    to    t    by
+            (_\bd_\be_\bc_\bl_\ba_\br_\be (_\bm_\ba_\bc_\br_\bo_\bs _\bt)).
+
+                 When a function or macro definition is com-
+            piled,  macro  expansion is done whenever possi-
+            ble.  If the compiler can determine that a  form
+            would  be evaluated if this function were inter-
+            preted then it will macro expand  it.   It  will
+            not  macro  expand arguments to a nlambda unless
+            the characteristics of the nlambda is known  (as
+            is  the  case  with  _\bc_\bo_\bn_\bd).  The map functions (
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                               12-5
+
+
+            _\bm_\ba_\bp, _\bm_\ba_\bp_\bc, _\bm_\ba_\bp_\bc_\ba_\br, and so on) are expanded to  a
+            _\bd_\bo statement.  This allows the first argument to
+            the map function to be a lambda expression which
+            references local variables of the function being
+            defined.
+
+
+
+         12.3.2.6.  other forms
+
+                 All other forms are simply  stored  in  the
+            object  file  and are evaluated when the file is
+            _\bf_\ba_\bs_\bled in.
+
+
+
+   12.4.  Using the compiler
+
+           The previous section describes exactly  what  the
+      compiler  does  with  its  input.  Generally you won't
+      have to worry about all that  detail  as  files  which
+      work  interpreted  will work compiled.  Following is a
+      list of steps you should follow to insure that a  file
+      will compile correctly.
+
+      [1]  Make sure all macro definitions precede their use
+           in  functions or other macro definitions.  If you
+           want the macros to be around when you _\bf_\ba_\bs_\bl in the
+           object  file you should include this statement at
+           the beginning of the file: (_\bd_\be_\bc_\bl_\ba_\br_\be (_\bm_\ba_\bc_\br_\bo_\bs _\bt))
+
+      [2]  Make sure all nlambdas are  defined  or  declared
+           before  they  are  used.   If  the compiler comes
+           across a call to a function which  has  not  been
+           defined  in  the  current  file,  which  does not
+           currently have a function binding, and whose type
+           has  not  been  declared then it will assume that
+           the function needs  its arguments evaluated (i.e.
+           it  is  a lambda or lexpr) and will generate code
+           accordingly.  This means that you do not have  to
+           declare  nlambda functions like _\bs_\bt_\ba_\bt_\bu_\bs since they
+           have an nlambda function binding.
+
+      [3]  Locate all variables which are used for  communi-
+           cating values between functions.  These variables
+           must be declared special at the  beginning  of  a
+           file.   In most cases there won't be many special
+           declarations but if you fail to declare  a  vari-
+           able  special  that  should be, the compiled code
+           could fail in mysterious ways.  Let's look  at  a
+           common  problem, assume that a file contains just
+           these three lines:
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                               12-6
+
+
+           (_\bd_\be_\bf _\ba_\ba_\ba (_\bl_\ba_\bm_\bb_\bd_\ba (_\bg_\bl_\bo_\bb _\bl_\bo_\bc) (_\bb_\bb_\bb _\bl_\bo_\bc)))
+           (_\bd_\be_\bf _\bb_\bb_\bb (_\bl_\ba_\bm_\bb_\bd_\ba (_\bm_\by_\bl_\bo_\bc) (_\ba_\bd_\bd _\bg_\bl_\bo_\bb _\bm_\by_\bl_\bo_\bc)))
+           (_\bd_\be_\bf _\bc_\bc_\bc (_\bl_\ba_\bm_\bb_\bd_\ba (_\bg_\bl_\bo_\bb _\bl_\bo_\bc) (_\bb_\bb_\bb _\bl_\bo_\bc)))
+
+
+           We can see that if we load in these  two  defini-
+           tions then (aaa 3 4) is the same as (add 3 4) and
+           will give us 7.  Suppose we compile the file con-
+           taining  these  definitions.  When Liszt compiles
+           aaa, it will assume that both glob  and  loc  are
+           local  variables  and  will allocate space on the
+           temporary stack for  their  values  when  aaa  is
+           called.   Thus  the values of the local variables
+           glob and loc will not affect the  values  of  the
+           symbols  glob  and  loc  in the Lisp system.  Now
+           Liszt moves on to function bbb.  Myloc is assumed
+           to  be local.  When it sees the add statement, it
+           find a reference to a variable called glob.  This
+           variable is not a local variable to this function
+           and therefore glob must refer to the value of the
+           symbol  glob.   Liszt  will automatically declare
+           glob to be special and it will print a warning to
+           that  effect.   Thus subsequent uses of glob will
+           always refer to the symbol glob.  Next Liszt com-
+           piles ccc and treats glob as a special and loc as
+           a local.  When the object file is _\bf_\ba_\bs_\bl'ed in, and
+           (ccc  3  4) is evaluated, the symbol glob will be
+           lambda bound to 3 bbb will  be  called  and  will
+           return 7.  However (aaa 3 4) will fail since when
+           bbb is called, glob will be unbound.  What should
+           be done here is to put (_\bd_\be_\bc_\bl_\ba_\br_\be (_\bs_\bp_\be_\bc_\bi_\ba_\bl _\bg_\bl_\bo_\bb) at
+           the beginning of the file.
+
+      [4]  Make sure that all calls to _\ba_\br_\bg  are  within  the
+           lexpr  whose arguments they reference.  If _\bf_\bo_\bo is
+           a compiled lexpr and it calls _\bb_\ba_\br then _\bb_\ba_\br cannot
+           use  _\ba_\br_\bg  to get at _\bf_\bo_\bo's arguments.  If both _\bf_\bo_\bo
+           and _\bb_\ba_\br are interpreted this will  work  however.
+           The  macro _\bl_\bi_\bs_\bt_\bi_\bf_\by can be used to put all of some
+           of a lexprs arguments in a list which then can be
+           passed to other functions.
+
+
+
+   12.5.  Compiler options
+
+           The compiler recognizes a number of options which
+      are  described  below.  The options are typed anywhere
+      on the command line preceded by  a  minus  sign.   The
+      entire   command  line  is  scanned  and  all  options
+      recorded before any action is taken.  Thus
+      % liszt -mx foo
+      % liszt -m -x foo
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                               12-7
+
+
+      % liszt foo -mx
+      are all equivalent. Before scanning the  command  line
+      for  options,  liszt  looks for in the environment for
+      the variable LISZT, and if found scans its value as if
+      it  was  a  string  of  options.   The  meaning of the
+      options are:
+
+      C    The assembler language output of the compiler  is
+           commented.   This  is  useful  when debugging the
+           compiler and is not normally done since it  slows
+           down compilation.
+
+      I    The next command line  argument  is  taken  as  a
+           filename, and loaded prior to compilation.
+
+      e    Evaluate the next argument on  the  command  line
+           before starting compilation.  For example
+           % liszt -e '(setq foobar "foo string")' foo
+           will evaluate the above s-expression.  Note  that
+           the  shell  requires  that  the arguments be sur-
+           rounded by single quotes.
+
+      i    Compile this program in  interlisp  compatibility
+           mode. This is not implemented yet.
+
+      m    Compile this program in Maclisp mode.  The reader
+           syntax  will be changed to the Maclisp syntax and
+           a file of macro definitions  will  be  loaded  in
+           (usually   named  /usr/lib/lisp/machacks).   This
+           switch brings us sufficiently close to Maclisp to
+           allow us to compile Macsyma, a large Maclisp pro-
+           gram.  However Maclisp is a moving target and  we
+           can't  guarantee  that this switch will allow you
+           to compile any given program.
+
+      o    Select a different object or  assembler  language
+           file name.  For example
+           % liszt foo -o xxx.o
+           will compile foo and into xxx.o  instead  of  the
+           default foo.o, and
+           % liszt bar -S -o xxx.s
+           will compile to  assembler  language  into  xxx.s
+           instead of bar.s.
+
+      p    place profiling code at  the  beginning  of  each
+           non-local  function.   If the lisp system is also
+           created with profiling in it, this  allows  func-
+           tion  calling  frequency  to  be  determined (see
+           _\bp_\br_\bo_\bf(_\b1))
+
+      q    Run in quiet mode. The names of  functions  being
+           compiled and various "Note"'s are not printed.
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                               12-8
+
+
+      Q    print compilation statistics and warn of  strange
+           constructs.  This  is the inverse of the q switch
+           and is the default.
+
+      r    place bootstrap code  at  the  beginning  of  the
+           object  file,  which when the object file is exe-
+           cuted will cause a lisp system to be invoked  and
+           the  object  file  _\bf_\ba_\bs_\bled  in.  This  is known as
+           `autorun' and is described below.
+
+      S    Create an assembler language file only.
+           % liszt -S foo
+           will create  the  file  assembler  language  file
+           foo.s  and  will  not attempt to assemble it.  If
+           this  option  is  not  specified,  the  assembler
+           language  file  will be put in the temporary disk
+           area under a automatically generated  name  based
+           on the lisp compiler's process id.  Then if there
+           are no compilation errors, the assembler will  be
+           invoked to assemble the file.
+
+      T    Print the assembler language output on the  stan-
+           dard  output file.  This is useful when debugging
+           the compiler.
+
+      u    Run in UCI-Lisp mode.  The  character  syntax  is
+           changed to that of UCI-Lisp and a UCI-Lisp compa-
+           tibility package of macros is read in.
+
+      w    Suppress warning messages.
+
+      x    Create an cross reference file.
+           % liszt -x foo
+           not only compiles foo into foo.o  but  also  gen-
+           erates  the file foo.x .  The file foo.x  is lisp
+           readable and lists for each  function  all  func-
+           tions  which  that function could call.  The pro-
+           gram lxref reads one or more of these ".x"  files
+           and  produces  a  human  readable cross reference
+           listing.
+
+
+
+   12.6.  autorun
+
+           The object  file which liszt writes does not con-
+      tain  all the functions necessary to run the lisp pro-
+      gram which was compiled.  In order to use  the  object
+      file,  a  lisp  system  must be started and the object
+      file _\bf_\ba_\bs_\bled in.  When the -r switch is given to liszt,
+      the  object file created will contain a small piece of
+      bootstrap code at the beginning, and the  object  file
+      will  be  made  executable.  Now, when the name of the
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                               12-9
+
+
+      object file is given to the UNIX  command  interpreter
+      (shell) to run, the bootstrap code at the beginning of
+      the object file will cause a lisp system to be started
+      and  the first action the lisp system will  take is to
+      _\bf_\ba_\bs_\bl in the object file which started it.   In  effect
+      the object file has created an environment in which it
+      can run.
+
+           Autorun  is  an  alternative  to  _\bd_\bu_\bm_\bp_\bl_\bi_\bs_\bp.   The
+      advantage  of  autorun  is  that the object file which
+      starts the whole process is typically  small,  whereas
+      the  minimum  _\bd_\bu_\bm_\bp_\bl_\bi_\bs_\bped  file is very large (one half
+      megabyte).  The disadvantage of autorun  is  that  the
+      file  must  be _\bf_\ba_\bs_\bled into a lisp each time it is used
+      whereas the file which _\bd_\bu_\bm_\bp_\bl_\bi_\bs_\bp creates can be run  as
+      is.   liszt  itself  is  a _\bd_\bu_\bm_\bp_\bl_\bi_\bs_\bped file since it is
+      used so often and is large enough that too  much  time
+      would  be  wasted _\bf_\ba_\bs_\bling it in each time it was used.
+      The lisp cross reference program, lxref, uses  _\ba_\bu_\bt_\bo_\br_\bu_\bn
+      since it is a small and rarely used program.
+
+           In order to have the program _\bf_\ba_\bs_\bled in begin exe-
+      cution  (rather  than  starting a lisp top level), the
+      value of the symbol user-top-level should  be  set  to
+      the  name  of the function to get control.  An example
+      of this is shown next.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                              12-10
+
+
+
+    ____________________________________________________
+
+    _\bw_\be _\bw_\ba_\bn_\bt _\bt_\bo _\br_\be_\bp_\bl_\ba_\bc_\be _\bt_\bh_\be _\bu_\bn_\bi_\bx _\bd_\ba_\bt_\be _\bp_\br_\bo_\bg_\br_\ba_\bm _\bw_\bi_\bt_\bh _\bo_\bn_\be _\bw_\br_\bi_\bt_\bt_\be_\bn _\bi_\bn _\bl_\bi_\bs_\bp.
+
+    % cat lispdate.l
+    (defun mydate nil
+       (patom "The date is ")
+       (patom (status ctime))
+       (terpr)
+       (exit 0))
+    (setq user-top-level 'mydate)
+
+    % liszt -r lispdate
+    Compilation begins with Lisp Compiler 5.2
+    source: lispdate.l, result: lispdate.o
+    mydate
+    %Note: lispdate.l: Compilation complete
+    %Note: lispdate.l:  Time: Real: 0:3, CPU: 0:0.28, GC: 0:0.00 for 0 gcs
+    %Note: lispdate.l: Assembly begins
+    %Note: lispdate.l: Assembly completed successfully
+    3.0u 2.0s 0:17 29%
+
+     _\bW_\be _\bc_\bh_\ba_\bn_\bg_\be _\bt_\bh_\be _\bn_\ba_\bm_\be _\bt_\bo _\br_\be_\bm_\bo_\bv_\be _\bt_\bh_\be "._\bo", (_\bt_\bh_\bi_\bs _\bi_\bs_\bn'_\bt _\bn_\be_\bc_\be_\bs_\bs_\ba_\br_\by)
+    % mv lispdate.o lispdate
+
+     _\bN_\bo_\bw _\bw_\be _\bt_\be_\bs_\bt _\bi_\bt _\bo_\bu_\bt
+    % lispdate
+    The date is Sat Aug  1 16:58:33 1981
+    %
+    ____________________________________________________
+
+
+
+
+
+
+   12.7.  pure literals
+
+           Normally the quoted lisp objects (literals) which
+      appear in functions are treated as constants. Consider
+      this function:
+
+      (_\bd_\be_\bf _\bf_\bo_\bo
+         (_\bl_\ba_\bm_\bb_\bd_\ba _\bn_\bi_\bl (_\bc_\bo_\bn_\bd ((_\bn_\bo_\bt (_\be_\bq '_\ba  (_\bc_\ba_\br  (_\bs_\be_\bt_\bq  _\bx  '(_\ba
+      _\bb)))))
+                            (_\bp_\br_\bi_\bn_\bt '_\bi_\bm_\bp_\bo_\bs_\bs_\bi_\bb_\bl_\be!!))
+                           (_\bt (_\br_\bp_\bl_\ba_\bc_\ba _\bx '_\bd)))))
+
+      At first glance it seems that the  first  cond  clause
+      will  never  be  true,  since  the _\bc_\ba_\br of (_\ba _\bb) should
+      always be _\ba.  However if you run this function  twice,
+      it will print 'impossible!!' the second time.  This is
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                              12-11
+
+
+      because the following clause modifies  the  'constant'
+      list  (_\ba _\bb)  with the _\br_\bp_\bl_\ba_\bc_\ba function.  Such modifica-
+      tion of literal lisp objects  can  cause  programs  to
+      behave  strangely as the above example shows, but more
+      importantly it can cause garbage  collection  problems
+      if  done  to compiled code.  When a file is _\bf_\ba_\bs_\bled in,
+      if the symbol $purcopylits is  non  nil,  the  literal
+      lisp  data  is  put in 'pure' space, that is it put in
+      space which needn't be looked at by the garabage  col-
+      lector.   This  reduces the work the garbage collector
+      must do but it is dangerous since if the literals  are
+      modified  to point to non pure objects, the marker may
+      not mark the non pure objects.  If  the  symbol  $pur-
+      copylits  is  nil then the literal lisp data is put in
+      impure space and the compiled code will act  like  the
+      interpreted  code  when literal data is modified.  The
+      default value for $purcopylits is t.
+
+
+
+   12.8.  transfer tables
+
+           A transfer table is setup by _\bf_\ba_\bs_\bl when the object
+      file is loaded in.  There is one entry in the transfer
+      table for each function which is called in that object
+      file.   The  entry  for a call to the function _\bf_\bo_\bo has
+      two parts whose contents are:
+
+      [1]  function address - This will initially  point  to
+           the internal  function _\bq_\bl_\bi_\bn_\bk_\be_\br.  It may some time
+           in the future point to the function _\bf_\bo_\bo  if  cer-
+           tain  conditions  are  satisfied  (more  on  this
+           below).
+
+      [2]  function name - This is a pointer to  the  symbol
+           _\bf_\bo_\bo.  This will be used by _\bq_\bl_\bi_\bn_\bk_\be_\br.
+
+
+
+      When a call is made to the function _\bf_\bo_\bo the call  will
+      actually  be made to the address in the transfer table
+      entry  and  will  end  up  in  the  _\bq_\bl_\bi_\bn_\bk_\be_\br  function.
+      _\bQ_\bl_\bi_\bn_\bk_\be_\br will determine that _\bf_\bo_\bo was the function being
+      called by locating the  function  name  entry  in  the
+      transfer table[].  If the function being called is not
+      compiled  then  _\bq_\bl_\bi_\bn_\bk_\be_\br  just calls _\bf_\bu_\bn_\bc_\ba_\bl_\bl to perform
+____________________
+\e9   []_\bQ_\bl_\bi_\bn_\bk_\be_\br does this by tracing back the call stack  until
+it finds the _\bc_\ba_\bl_\bl_\bs machine instruction which called it.  The
+address field of the  _\bc_\ba_\bl_\bl_\bs  contains  the  address  of  the
+transfer table entry.
+
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Liszt - the lisp compiler                              12-12
+
+
+      the  function  call.   If  _\bf_\bo_\bo  is  compiled  and   if
+      (_\bs_\bt_\ba_\bt_\bu_\bs _\bt_\br_\ba_\bn_\bs_\bl_\bi_\bn_\bk)  is  non  nil,  then  _\bq_\bl_\bi_\bn_\bk_\be_\br  will
+      modify the function address part of the transfer table
+      to  point  directly  to  the  function  _\bf_\bo_\bo.   Finally
+      _\bq_\bl_\bi_\bn_\bk_\be_\br will call _\bf_\bo_\bo directly .  The next time a call
+      is  made  to  _\bf_\bo_\bo the call will go directly to _\bf_\bo_\bo and
+      not through _\bq_\bl_\bi_\bn_\bk_\be_\br.  This will result in  a  substan-
+      tial   speedup  in  compiled  code  to  compiled  code
+      transfers.  A disadvantage is that no debugging infor-
+      mation is left on the stack, so _\bs_\bh_\bo_\bw_\bs_\bt_\ba_\bc_\bk and _\bb_\ba_\bk_\bt_\br_\ba_\bc_\be
+      are useless.  Another  disadvantage  is  that  if  you
+      redefine a compiled function either through loading in
+      a new version or interactively defining it,  then  the
+      old  version may still be called from compiled code if
+      the fast linking  described  above  has  already  been
+      done.   The  solution  to  these  problems  is  to use
+      (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bt_\br_\ba_\bn_\bs_\bl_\bi_\bn_\bk _\bv_\ba_\bl_\bu_\be).  If value is
+
+      _\bn_\bi_\bl  All transfer tables will  be  cleared,  i.e.  all
+           function  addresses  will  be  set  to  point  to
+           _\bq_\bl_\bi_\bn_\bk_\be_\br.  This means that the next time  a  func-
+           tion  is  called  _\bq_\bl_\bi_\bn_\bk_\be_\br will be called and will
+           look at the current definition.   Also,  no  fast
+           links  will  be  set  up since (_\bs_\bt_\ba_\bt_\bu_\bs _\bt_\br_\ba_\bn_\bs_\bl_\bi_\bn_\bk)
+           will be nil.  The end result  is  that  _\bs_\bh_\bo_\bw_\bs_\bt_\ba_\bc_\bk
+           and  _\bb_\ba_\bk_\bt_\br_\ba_\bc_\be  will work and the function defini-
+           tion at the time of call will always be used.
+
+      _\bo_\bn   This causes the lisp system  to  go  through  all
+           transfer  tables  and  set up fast links wherever
+           possible.  This is normally used after  you  have
+           _\bf_\ba_\bs_\bled  in  all  of your files. Furthermore since
+           (_\bs_\bt_\ba_\bt_\bu_\bs _\bt_\br_\ba_\bn_\bs_\bl_\bi_\bn_\bk) is not nil, _\bq_\bl_\bi_\bn_\bk_\be_\br will  make
+           new  fast  links  if  the situation arises (which
+           isn't likely unless you _\bf_\ba_\bs_\bl in another file).
+
+      _\bt    This or any other value not previously  mentioned
+           will just make (_\bs_\bt_\ba_\bt_\bu_\bs _\bt_\br_\ba_\bn_\bs_\bl_\bi_\bn_\bk) be non nil, and
+           as a result fast links will be made   by  _\bq_\bl_\bi_\bn_\bk_\be_\br
+           if the called function is compiled.
+
+
+
+   12.9.  Fixnum functions
+
+           The compiler will generate inline arithmetic code
+      for  fixnum only functions.  Such functions include +,
+      -, *,  /, \, 1+ and 1-.  The code  generated  will  be
+      much  faster than using _\ba_\bd_\bd, _\bd_\bi_\bf_\bf_\be_\br_\be_\bn_\bc_\be, etc.  However
+      it will only work if the arguments to and  results  of
+      the functions are fixnums.  No type checking is done.
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/manual/ch2.r b/usr/src/ucb/lisp/lisplib/manual/ch2.r
new file mode 100644 (file)
index 0000000..3fae24b
--- /dev/null
@@ -0,0 +1,2494 @@
+
+
+
+
+
+
+
+                         CHAPTER  2
+
+
+                   Data Structure Access
+
+
+
+
+     The following functions allow one to create and manipu-
+late  the  various  types of lisp data structures.  Refer to
+1.2 for details of the data structures known to FRANZ LISP.
+
+
+
+   2.1.  Lists
+
+           The following functions exist  for  the  creation
+      and  manipulating  of  lists.  Lists are composed of a
+      linked list of objects  called  either  'list  cells',
+      'cons cells' or 'dtpr cells'.  Lists are normally ter-
+      minated with the special symbol nil.  nil  is  both  a
+      symbol and a representation for the empty list ().
+
+
+
+      2.1.1.  list creation
+
+(cons 'g_arg1 'g_arg2)
+
+     RETURNS: a new list cell whose car is g_arg1 and  whose
+              cdr is g_arg2.
+
+(xcons 'g_arg1 'g_arg2)
+
+     EQUIVALENT TO: (_\bc_\bo_\bn_\bs '_\bg__\ba_\br_\bg_\b2 '_\bg__\ba_\br_\bg_\b1)
+
+(ncons 'g_arg)
+
+     EQUIVALENT TO: (_\bc_\bo_\bn_\bs '_\bg__\ba_\br_\bg _\bn_\bi_\bl)
+
+(list ['g_arg1 ... ])
+
+     RETURNS: a list whose elements are the g_arg_\bi.
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9Data Structure Access                                    2-1
+
+
+
+
+
+
+
+Data Structure Access                                    2-2
+
+
+(append 'l_arg1 'l_arg2)
+
+     RETURNS: a list containing the elements of l_arg1  fol-
+              lowed by l_arg2.
+
+     NOTE: To generate the result, the top level list  cells
+           of  l_arg1 are duplicated and the cdr of the last
+           list cell is set to point to l_arg2.   Thus  this
+           is  an  expensive  operation  if l_arg1 is large.
+           See the  descriptions  of  _\bn_\bc_\bo_\bn_\bc  and  _\bt_\bc_\bo_\bn_\bc  for
+           cheaper  ways  of  doing  the  _\ba_\bp_\bp_\be_\bn_\bd if the list
+           l_arg1 can be altered.
+
+(append1 'l_arg1 'g_arg2)
+
+     RETURNS: a list like l_arg1 with  g_arg2  as  the  last
+              element.
+
+     NOTE: this  is  equivalent  to  (append  'l_arg1  (list
+           'g_arg2)).
+
+
+    ____________________________________________________
+
+    ; A common mistake is using append to add one element to the end of a list
+    -> (_\ba_\bp_\bp_\be_\bn_\bd '(_\ba _\bb _\bc _\bd) '_\be)
+    (a b c d . e)
+    ; The user intended to say:
+    -> (_\ba_\bp_\bp_\be_\bn_\bd '(_\ba _\bb _\bc _\bd) '(_\be))
+    (_\ba _\bb _\bc _\bd _\be)
+    ; _\bb_\be_\bt_\bt_\be_\br _\bi_\bs _\ba_\bp_\bp_\be_\bn_\bd_\b1
+    -> (_\ba_\bp_\bp_\be_\bn_\bd_\b1 '(_\ba _\bb _\bc _\bd) '_\be)
+    (_\ba _\bb _\bc _\bd _\be)
+    ____________________________________________________
+
+
+
+
+(quote! [g_qform_\bi] ...[! 'g_eform_\bi] ...  [!! 'l_form_\bi] ...)
+
+     RETURNS: The list  resulting  from  the   splicing  and
+              insertion process described below.
+
+     NOTE: _\bq_\bu_\bo_\bt_\be!  is the complement of the  _\bl_\bi_\bs_\bt  function.
+           _\bl_\bi_\bs_\bt  forms  a list by evaluating each for in the
+           argument list; evaluation is  suppressed  if  the
+           form  is _\bq_\bu_\bo_\bt_\beed.  In _\bq_\bu_\bo_\bt_\be!, each form is impli-
+           citly _\bq_\bu_\bo_\bt_\beed.  To be evaluated, a form  must  be
+           preceded  by one of the evaluate operations ! and
+           !!. ! g_eform evaluates g_form and the  value  is
+           inserted  in  the  place  of  the call; !! l_form
+           evaluates l_form and the value  is  spliced  into
+           the place of the call.
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                    2-3
+
+
+           `Splicing in' means  that  the  parentheses  sur-
+           rounding  the  list  are  removed  as the example
+           below shows.  Use of the evaluate  operators  can
+           occur at any level in a form argument.
+
+           Another way to get the effect of the _\bq_\bu_\bo_\bt_\be! func-
+           tion is to use the backquote character macro (see
+            8.3.3).
+
+
+    ____________________________________________________
+
+    (_\bq_\bu_\bo_\bt_\be! _\bc_\bo_\bn_\bs ! (_\bc_\bo_\bn_\bs _\b1 _\b2) _\b3) = (_\bc_\bo_\bn_\bs (_\b1 . _\b2) _\b3)
+    (_\bq_\bu_\bo_\bt_\be! _\b1 !! (_\bl_\bi_\bs_\bt _\b2 _\b3 _\b4) _\b5) = (_\b1 _\b2 _\b3 _\b4 _\b5)
+    (_\bs_\be_\bt_\bq _\bq_\bu_\bo_\bt_\be_\bd '_\be_\bv_\ba_\bl_\be_\bd)(_\bq_\bu_\bo_\bt_\be! ! ((_\bI _\ba_\bm  ! _\bq_\bu_\bo_\bt_\be_\bd))) = ((_\bI _\ba_\bm _\be_\bv_\ba_\bl_\be_\bd))
+    (_\bq_\bu_\bo_\bt_\be! _\bt_\br_\by ! '(_\bt_\bh_\bi_\bs ! _\bo_\bn_\be)) = (_\bt_\br_\by (_\bt_\bh_\bi_\bs ! _\bo_\bn_\be))
+    ____________________________________________________
+
+
+
+
+
+(bignum-to-list 'b_arg)
+
+     RETURNS: A list  of  the  fixnums  which  are  used  to
+              represent the bignum.
+
+     NOTE: the inverse of this function is _\bl_\bi_\bs_\bt-_\bt_\bo-_\bb_\bi_\bg_\bn_\bu_\bm.
+
+(list-to-bignum 'l_ints)
+
+     WHERE:   l_ints is a list of fixnums.
+
+     RETURNS: a bignum constructed of the given fixnums.
+
+     NOTE: the inverse of this function is _\bb_\bi_\bg_\bn_\bu_\bm-_\bt_\bo-_\bl_\bi_\bs_\bt.
+
+
+
+
+      2.1.2.  list predicates
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                    2-4
+
+
+(dtpr 'g_arg)
+
+     RETURNS: t iff g_arg is a list cell.
+
+     NOTE: that (dtpr '()) is nil.
+
+(listp 'g_arg)
+
+     RETURNS: t iff g_arg is a list object or nil.
+
+(tailp 'l_x 'l_y)
+
+     RETURNS: l_x, if a list cell _\be_\bq  to  l_x  is  found  by
+              _\bc_\bd_\bring down l_y zero or more times, nil other-
+              wise.
+
+
+    ____________________________________________________
+
+    -> (_\bs_\be_\bt_\bq _\bx '(_\ba _\bb _\bc _\bd) _\by (_\bc_\bd_\bd_\br _\bx))
+    (c d)
+    -> (_\ba_\bn_\bd (_\bd_\bt_\bp_\br _\bx) (_\bl_\bi_\bs_\bt_\bp _\bx))     ; x and y are dtprs and lists
+    t
+    -> (_\bd_\bt_\bp_\br '())           ; () is the same as nil and is not a dtpr
+    nil
+    -> (_\bl_\bi_\bs_\bt_\bp '())          ; however it is a list
+    t
+    -> (_\bt_\ba_\bi_\bl_\bp _\by _\bx)
+    (c d)
+    ____________________________________________________
+
+
+
+
+(length 'l_arg)
+
+     RETURNS: the number of elements in  the  top  level  of
+              list l_arg.
+
+
+
+      2.1.3.  list accessing
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                    2-5
+
+
+(car 'l_arg)
+(cdr 'l_arg)
+
+     RETURNS: _\bc_\bo_\bn_\bs cell.  (_\bc_\ba_\br (_\bc_\bo_\bn_\bs x y)) is always x, (_\bc_\bd_\br
+              (_\bc_\bo_\bn_\bs  x  y)) is always y.  In FRANZ LISP, the
+              cdr portion is located first in memory.   This
+              is hardly noticeable, and seems to bother few.
+
+(c..r 'lh_arg)
+
+     WHERE:   the .. represents any positive number  of  a's
+              and d's.
+
+     RETURNS: the result of accessing the list structure  in
+              the  way determined by the function name.  The
+              a's and d's are read from right to left,  a  d
+              directing  the access down the cdr part of the
+              list cell and an a down the car part.
+
+     NOTE: lh_arg may also be nil, and it is guaranteed that
+           the  car  and  cdr of nil is nil.  If lh_arg is a
+           hunk,  then  (_\bc_\ba_\br '_\bl_\bh__\ba_\br_\bg)   is   the   same   as
+           (_\bc_\bx_\br _\b1 '_\bl_\bh__\ba_\br_\bg) and  (_\bc_\bd_\br '_\bl_\bh__\ba_\br_\bg) is the same as
+           (_\bc_\bx_\br _\b0 '_\bl_\bh__\ba_\br_\bg).
+           It is generally hard to read and  understand  the
+           context  of  functions  with large strings of a's
+           and d's, but these  functions  are  supported  by
+           rapid  accessing  and open-compiling (see Chapter
+           12).
+
+(nth 'x_index 'l_list)
+
+     RETURNS: the nth element of l_list, assuming zero-based
+              index.   Thus  (nth  0  l_list) is the same as
+              (car l_list).  _\bn_\bt_\bh is both a function,  and  a
+              compiler  macro,  so  that more efficient code
+              might be generated than for _\bn_\bt_\bh_\be_\bl_\be_\bm (described
+              below).
+
+     NOTE: If x_arg1 is non-positive  or  greater  than  the
+           length of the list, nil is returned.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                    2-6
+
+
+(nthcdr 'x_index 'l_list)
+
+     RETURNS: the result of  _\bc_\bd_\bring  down  the  list  l_list
+              x_index times.
+
+     NOTE: If    x_index    is    less    than    0,    then
+           (_\bc_\bo_\bn_\bs _\bn_\bi_\bl '_\bl__\bl_\bi_\bs_\bt) is returned.
+
+(nthelem 'x_arg1 'l_arg2)
+
+     RETURNS: The x_arg1'_\bs_\bt element of the list l_arg2.
+
+     NOTE: This function comes from the PDP-11 lisp system.
+
+(last 'l_arg)
+
+     RETURNS: the last list cell in the list l_arg.
+
+     EXAMPLE: _\bl_\ba_\bs_\bt does NOT return the  last  element  of  a
+              list!
+              (_\bl_\ba_\bs_\bt '(_\ba _\bb)) = (b)
+
+(ldiff 'l_x 'l_y)
+
+     RETURNS: a  list  of all elements in l_x but not in l_y
+              , i.e., the list difference of l_x and l_y.
+
+     NOTE: l_y must be a tail of l_x, i.e., _\be_\bq to the result
+           of  applying  some  number  of _\bc_\bd_\br's to l_x. Note
+           that  the  value   of   _\bl_\bd_\bi_\bf_\bf   is   always   new
+           list  structure  unless l_y is nil, in which case
+           (_\bl_\bd_\bi_\bf_\bf _\bl__\bx _\bn_\bi_\bl) is l_x itself.  If l_y   is   not
+           a  tail  of  l_x, _\bl_\bd_\bi_\bf_\bf generates an error.
+
+     EXAMPLE: (_\bl_\bd_\bi_\bf_\bf '_\bl__\bx (_\bm_\be_\bm_\bb_\be_\br '_\bg__\bf_\bo_\bo  '_\bl__\bx))  gives  all
+              elements in l_x up to the first g_foo.
+
+
+
+      2.1.4.  list manipulation
+
+(rplaca 'lh_arg1 'g_arg2)
+
+     RETURNS: the modified lh_arg1.
+
+     SIDE EFFECT: the car of lh_arg1 is set to  g_arg2.   If
+                  lh_arg1  is a hunk then the second element
+                  of the hunk is set to g_arg2.
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                    2-7
+
+
+(rplacd 'lh_arg1 'g_arg2)
+
+     RETURNS: the modified lh_arg1.
+
+     SIDE EFFECT: the cdr of lh_arg2 is set to  g_arg2.   If
+                  lh_arg1  is  a hunk then the first element
+                  of the hunk is set to g_arg2.
+
+
+(attach 'g_x 'l_l)
+
+     RETURNS: l_l whose _\bc_\ba_\br is now g_x, whose  _\bc_\ba_\bd_\br  is  the
+              original (_\bc_\ba_\br _\bl__\bl), and whose _\bc_\bd_\bd_\br is the ori-
+              ginal (_\bc_\bd_\br _\bl__\bl).
+
+     NOTE: what happens is that g_x is added to  the  begin-
+           ning  of  list l_l  yet maintaining the same list
+           cell  at the beginning of the list.
+
+(delete 'g_val 'l_list ['x_count])
+
+     RETURNS: the result of  splicing  g_val  from  the  top
+              level of l_list no more than x_count times.
+
+     NOTE: x_count defaults to a very large number, thus  if
+           x_count  is  not  given, all occurrences of g_val
+           are removed from the top level of l_list.   g_val
+           is compared with successive _\bc_\ba_\br's of l_list using
+           the function _\be_\bq_\bu_\ba_\bl.
+
+     SIDE EFFECT: l_list is modified using  rplacd,  no  new
+                  list cells are used.
+
+(delq 'g_val 'l_list ['x_count])
+(dremove 'g_val 'l_list ['x_count])
+
+     RETURNS: the result of  splicing  g_val  from  the  top
+              level of l_list no more than x_count times.
+
+     NOTE: _\bd_\be_\bl_\bq (and _\bd_\br_\be_\bm_\bo_\bv_\be) are the same as _\bd_\be_\bl_\be_\bt_\be  except
+           that _\be_\bq is used for comparison instead of _\be_\bq_\bu_\ba_\bl.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                    2-8
+
+
+
+    ____________________________________________________
+
+    ; note that you should use the value returned by _\bd_\be_\bl_\be_\bt_\be or _\bd_\be_\bl_\bq
+    ; and not assume that g_val will always show the deletions.
+    ; For example
+
+    -> (_\bs_\be_\bt_\bq _\bt_\be_\bs_\bt '(_\ba _\bb _\bc _\ba _\bd _\be))
+    (a b c a d e)
+    -> (_\bd_\be_\bl_\be_\bt_\be '_\ba _\bt_\be_\bs_\bt)
+    (b c d e)         ; the value returned is what we would expect
+    -> _\bt_\be_\bs_\bt
+    (a b c d e)       ; but test still has the first a in the list!
+    ____________________________________________________
+
+
+
+
+(remq 'g_x 'l_l ['x_count])
+(remove 'g_x 'l_l)
+
+     RETURNS: a _\bc_\bo_\bp_\by of l_l  with  all  top  level  elements
+              _\be_\bq_\bu_\ba_\bl to g_x removed.  _\br_\be_\bm_\bq uses _\be_\bq instead of
+              _\be_\bq_\bu_\ba_\bl for comparisons.
+
+     NOTE: remove does not modify its arguments like _\bd_\be_\bl_\be_\bt_\be,
+           and _\bd_\be_\bl_\bq do.
+
+(insert 'g_object 'l_list 'u_comparefn 'g_nodups)
+
+     RETURNS: a list consisting of l_list with g_object des-
+              tructively  inserted  in a place determined by
+              the ordering function u_comparefn.
+
+     NOTE: (_\bc_\bo_\bm_\bp_\ba_\br_\be_\bf_\bn '_\bg__\bx  '_\bg__\by)  should  return  something
+           non-nil  if  g_x can precede g_y in sorted order,
+           nil if g_y must precede g_x.  If  u_comparefn  is
+           nil, alphabetical order will be used. If g_nodups
+           is non-nil, an element will not be inserted if an
+           equal  element  is  already  in the list.  _\bi_\bn_\bs_\be_\br_\bt
+           does binary search to determine where  to  insert
+           the new element.
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                    2-9
+
+
+(merge 'l_data1 'l_data2 'u_comparefn)
+
+     RETURNS: the merged list of the two input sorted  lists
+              l_data1  and  l_data1  using binary comparison
+              function u_comparefn.
+
+     NOTE: (_\bc_\bo_\bm_\bp_\ba_\br_\be_\bf_\bn '_\bg__\bx  '_\bg__\by)  should  return  something
+           non-nil  if  g_x can precede g_y in sorted order,
+           nil if g_y must precede g_x.  If  u_comparefn  is
+           nil,    alphabetical    order   will   be   used.
+           u_comparefn should be thought of as "less than or
+           equal".   _\bm_\be_\br_\bg_\be  changes  both  of its data argu-
+           ments.
+
+(subst 'g_x 'g_y 'l_s)
+(dsubst 'g_x 'g_y 'l_s)
+
+     RETURNS: the result of substituting g_x for  all  _\be_\bq_\bu_\ba_\bl
+              occurrences of g_y  at all levels in l_s.
+
+     NOTE: If g_y is a symbol, _\be_\bq will be used for comparis-
+           ons.   The function _\bs_\bu_\bb_\bs_\bt does not modify l_s but
+           the function  _\bd_\bs_\bu_\bb_\bs_\bt  (destructive  substitution)
+           does.
+
+(lsubst 'l_x 'g_y 'l_s)
+
+     RETURNS: a copy of l_s  with l_x spliced in  for  every
+              occurrence  of  of g_y at all levels. Splicing
+              in means that the parentheses surrounding  the
+              list  l_x  are  removed  as  the example below
+              shows.
+
+
+    ____________________________________________________
+
+    -> (_\bs_\bu_\bb_\bs_\bt '(_\ba _\bb _\bc) '_\bx '(_\bx _\by _\bz (_\bx _\by _\bz) (_\bx _\by _\bz)))
+    ((a b c) y z ((a b c) y z) ((a b c) y z))
+    -> (_\bl_\bs_\bu_\bb_\bs_\bt '(_\ba _\bb _\bc) '_\bx '(_\bx _\by _\bz (_\bx _\by _\bz) (_\bx _\by _\bz)))
+    (a b c y z (a b c y z) (a b c y z))
+    ____________________________________________________
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-10
+
+
+(subpair 'l_old 'l_new 'l_expr)
+
+     WHERE:   there are  the  same  number  of  elements  in
+              l_old as l_new.
+
+     RETURNS: the list l_expr  with  all  occurrences  of  a
+              object  in l_old replaced by the corresponding
+              one in l_new.  When a substitution is made,  a
+              copy  of  the  value  to  substitute in is not
+              made.
+
+     EXAMPLE: (_\bs_\bu_\bb_\bp_\ba_\bi_\br '(_\ba _\bc)' (_\bx _\by) '(_\ba _\bb _\bc _\bd)) = (_\bx _\bb _\by _\bd)
+
+
+(nconc 'l_arg1 'l_arg2 ['l_arg3 ...])
+
+     RETURNS: A list consisting of the  elements  of  l_arg1
+              followed by the elements of l_arg2 followed by
+              l_arg3 and so on.
+
+     NOTE: The _\bc_\bd_\br of  the  last  list  cell  of  l_arg_\bi  is
+           changed to point to l_arg_\bi+_\b1.
+
+
+    ____________________________________________________
+
+    ; _\bn_\bc_\bo_\bn_\bc is faster than _\ba_\bp_\bp_\be_\bn_\bd because it doesn't allocate new list cells.
+    -> (_\bs_\be_\bt_\bq _\bl_\bi_\bs_\b1 '(_\ba _\bb _\bc))
+    (a b c)
+    -> (_\bs_\be_\bt_\bq _\bl_\bi_\bs_\b2 '(_\bd _\be _\bf))
+    (d e f)
+    -> (_\ba_\bp_\bp_\be_\bn_\bd _\bl_\bi_\bs_\b1 _\bl_\bi_\bs_\b2)
+    (a b c d e f)
+    -> _\bl_\bi_\bs_\b1
+    (a b c)       ; note that lis1 has not been changed by _\ba_\bp_\bp_\be_\bn_\bd
+    -> (_\bn_\bc_\bo_\bn_\bc _\bl_\bi_\bs_\b1 _\bl_\bi_\bs_\b2)
+    (a b c d e f) ; _\bn_\bc_\bo_\bn_\bc returns the same value as _\ba_\bp_\bp_\be_\bn_\bd
+    -> _\bl_\bi_\bs_\b1
+    (a b c d e f) ; but in doing so alters lis1
+    ____________________________________________________
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-11
+
+
+(reverse 'l_arg)
+(nreverse 'l_arg)
+
+     RETURNS: the list l_arg with the elements  at  the  top
+              level in reverse  order.
+
+     NOTE: The function _\bn_\br_\be_\bv_\be_\br_\bs_\be does the reversal in place,
+           that is the list structure is modified.
+
+(nreconc 'l_arg 'g_arg)
+
+     EQUIVALENT TO: (_\bn_\bc_\bo_\bn_\bc (_\bn_\br_\be_\bv_\be_\br_\bs_\be '_\bl__\ba_\br_\bg) '_\bg__\ba_\br_\bg)
+
+
+
+
+   2.2.  Predicates
+
+           The following functions test  for  properties  of
+      data  objects.  When  the result of the test is either
+      'false' or 'true',  then  nil  will  be  returned  for
+      'false' and something other than nil (often t) will be
+      returned for 'true'.
+
+(arrayp 'g_arg)
+
+     RETURNS: t iff g_arg is of type array.
+
+(atom 'g_arg)
+
+     RETURNS: t iff g_arg is not a list or hunk object.
+
+     NOTE: (_\ba_\bt_\bo_\bm '()) returns t.
+
+(bcdp 'g_arg)
+
+     RETURNS: t iff g_arg is a data object of type binary.
+
+     NOTE: the name of this function is a throwback  to  the
+           PDP-11 Lisp system.
+
+(bigp 'g_arg)
+
+     RETURNS: t iff g_arg is a bignum.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-12
+
+
+(dtpr 'g_arg)
+
+     RETURNS: t iff g_arg is a list cell.
+
+     NOTE: that (dtpr '()) is nil.
+
+(hunkp 'g_arg)
+
+     RETURNS: t iff g_arg is a hunk.
+
+(listp 'g_arg)
+
+     RETURNS: t iff g_arg is a list object or nil.
+
+(stringp 'g_arg)
+
+     RETURNS: t iff g_arg is a string.
+
+(symbolp 'g_arg)
+
+     RETURNS: t iff g_arg is a symbol.
+
+(valuep 'g_arg)
+
+     RETURNS: t iff g_arg is a value cell
+
+(vectorp 'v_vector)
+
+     RETURNS: t iff the argument is a vector.
+
+(vectorip 'v_vector)
+
+     RETURNS: t iff the argument is an immediate-vector.
+
+(type 'g_arg)
+(typep 'g_arg)
+
+     RETURNS: a symbol whose pname  describes  the  type  of
+              g_arg.
+
+(signp s_test 'g_val)
+
+     RETURNS: t iff g_val is a number  and  the  given  test
+              s_test on g_val returns true.
+
+     NOTE: The fact that _\bs_\bi_\bg_\bn_\bp simply returns nil  if  g_val
+           is  not  a  number is probably the most important
+           reason that _\bs_\bi_\bg_\bn_\bp is used.  The permitted  values
+           for  s_test  and what they mean are given in this
+           table.
+
+\e9
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-13
+
+
+\e8                         ____________________
+                          s_test   tested
+
+\e8                         ____________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b____________________
+                          l        g_val < 0
+                          le       g_val <\b_ 0
+                          e        g_val = 0
+                          n        g_val =\b/ 0
+                          ge       g_val >\b_ 0
+                          g        g_val > 0
+\e8                         ____________________
+\e7                        |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+                                            |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+(eq 'g_arg1 'g_arg2)
+
+     RETURNS: t if g_arg1 and g_arg2 are the exact same lisp
+              object.
+
+     NOTE: _\bE_\bq simply tests if g_arg1 and g_arg2 are  located
+           in  the exact same place in memory.  Lisp objects
+           which print the same are not necessarily _\be_\bq.  The
+           only  objects  guaranteed  to  be _\be_\bq are interned
+           symbols with the same print name.  [Unless a sym-
+           bol  is  created  in  a special way (such as with
+           _\bu_\bc_\bo_\bn_\bc_\ba_\bt or _\bm_\ba_\bk_\bn_\ba_\bm) it will be interned.]
+
+(neq 'g_x 'g_y)
+
+     RETURNS: t if g_x is not _\be_\bq to g_y, otherwise nil.
+
+(equal 'g_arg1 'g_arg2)
+(eqstr 'g_arg1 'g_arg2)
+
+     RETURNS: t iff g_arg1 and g_arg2 have the  same  struc-
+              ture as described below.
+
+     NOTE: g_arg and g_arg2 are _\be_\bq_\bu_\ba_\bl if
+
+     (1)  they are _\be_\bq.
+
+     (2)  they are both fixnums with the same value
+
+     (3)  they are both flonums with the same value
+
+     (4)  they are both bignums with the same value
+
+     (5)  they are both strings and are identical.
+
+     (6)  they are both lists and their cars  and  cdrs  are
+          _\be_\bq_\bu_\ba_\bl.
+
+
+
+
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-14
+
+
+
+    ____________________________________________________
+
+    ; _\be_\bq is much faster than _\be_\bq_\bu_\ba_\bl, especially in compiled code,
+    ; however you cannot use _\be_\bq to test for equality of numbers outside
+    ; of the range -1024 to 1023.  _\be_\bq_\bu_\ba_\bl will always work.
+    -> (_\be_\bq _\b1_\b0_\b2_\b3 _\b1_\b0_\b2_\b3)
+    t
+    -> (_\be_\bq _\b1_\b0_\b2_\b4 _\b1_\b0_\b2_\b4)
+    nil
+    -> (_\be_\bq_\bu_\ba_\bl _\b1_\b0_\b2_\b4 _\b1_\b0_\b2_\b4)
+    t
+    ____________________________________________________
+
+
+
+
+
+(not 'g_arg)
+(null 'g_arg)
+
+     RETURNS: t iff g_arg is nil.
+
+
+(member 'g_arg1 'l_arg2)
+(memq 'g_arg1 'l_arg2)
+
+     RETURNS: that part of the  l_arg2  beginning  with  the
+              first  occurrence of g_arg1.  If g_arg1 is not
+              in the top level of l_arg2, nil is returned.
+
+     NOTE: _\bm_\be_\bm_\bb_\be_\br tests for equality with _\be_\bq_\bu_\ba_\bl, _\bm_\be_\bm_\bq  tests
+           for equality with _\be_\bq.
+
+
+
+
+   2.3.  Symbols and Strings
+
+           In many of the following functions  the  distinc-
+      tion  between symbols and strings is somewhat blurred.
+      To remind ourselves of the difference, a string  is  a
+      null terminated sequence of characters, stored as com-
+      pactly as possible.  Strings are used as constants  in
+      FRANZ  LISP.   They  _\be_\bv_\ba_\bl to themselves.  A symbol has
+      additional structure: a value, property list, function
+      binding,  as  well  as its external representation (or
+      print-name).  If a symbol  is  given  to  one  of  the
+      string  manipulation  functions  below, its print name
+      will be used.
+
+           Another popular way to represent strings in  Lisp
+      is  as  a  list of fixnums which represent characters.
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-15
+
+
+      The suffix 'n' to a string manipulation function indi-
+      cates that it returns a string in this form.
+
+
+
+      2.3.1.  symbol and string creation
+
+(concat ['stn_arg1 ... ])
+(uconcat ['stn_arg1 ... ])
+
+     RETURNS: a symbol whose print name  is  the  result  of
+              concatenating  the print names, string charac-
+              ters  or  numerical  representations  of   the
+              sn_arg_\bi.
+
+     NOTE: If no arguments are given, a symbol with  a  null
+           pname  is  returned.   _\bc_\bo_\bn_\bc_\ba_\bt  places  the symbol
+           created on the oblist, the function _\bu_\bc_\bo_\bn_\bc_\ba_\bt  does
+           the  same thing but does not place the new symbol
+           on the oblist.
+
+     EXAMPLE: (_\bc_\bo_\bn_\bc_\ba_\bt '_\ba_\bb_\bc (_\ba_\bd_\bd _\b3 _\b4) "_\bd_\be_\bf") = abc7def
+
+(concatl 'l_arg)
+
+     EQUIVALENT TO: (_\ba_\bp_\bp_\bl_\by '_\bc_\bo_\bn_\bc_\ba_\bt '_\bl__\ba_\br_\bg)
+
+
+(implode 'l_arg)
+(maknam 'l_arg)
+
+     WHERE:   l_arg is a list of symbols, strings and  small
+              fixnums.
+
+     RETURNS: The symbol whose print name is the  result  of
+              concatenating  the  first  characters  of  the
+              print names of the symbols and strings in  the
+              list.    Any  fixnums  are  converted  to  the
+              equivalent ascii character.  In order to  con-
+              catenate  entire  strings  or print names, use
+              the function _\bc_\bo_\bn_\bc_\ba_\bt.
+
+     NOTE: _\bi_\bm_\bp_\bl_\bo_\bd_\be interns the  symbol  it  creates,  _\bm_\ba_\bk_\bn_\ba_\bm
+           does not.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-16
+
+
+(gensym ['s_leader])
+
+     RETURNS: a new uninterned atom beginning with the first
+              character  of  s_leader's  pname, or beginning
+              with g if s_leader is not given.
+
+     NOTE: The  symbol  looks  like  x0nnnnn  where   x   is
+           s_leader's  first  character  and  nnnnn  is  the
+           number of times you have called gensym.
+
+(copysymbol 's_arg 'g_pred)
+
+     RETURNS: an uninterned symbol with the same print  name
+              as  s_arg.   If  g_pred  is  non nil, then the
+              value, function binding and property  list  of
+              the new symbol are made _\be_\bq to those of s_arg.
+
+
+(ascii 'x_charnum)
+
+     WHERE:   x_charnum is between 0 and 255.
+
+     RETURNS: a symbol whose print name is the single  char-
+              acter    whose    fixnum   representation   is
+              x_charnum.
+
+
+(intern 's_arg)
+
+     RETURNS: s_arg
+
+     SIDE EFFECT: s_arg is put on the oblist if  it  is  not
+                  already there.
+
+(remob 's_symbol)
+
+     RETURNS: s_symbol
+
+     SIDE EFFECT: s_symbol is removed from the oblist.
+
+(rematom 's_arg)
+
+     RETURNS: t if s_arg is indeed an atom.
+
+     SIDE EFFECT: s_arg is  put  on  the  free  atoms  list,
+                  effectively reclaiming an atom cell.
+
+     NOTE: This function does _\bn_\bo_\bt check to see if  s_arg  is
+           on  the  oblist  or is referenced anywhere.  Thus
+           calling _\br_\be_\bm_\ba_\bt_\bo_\bm on an  atom  in  the  oblist  may
+           result in disaster when that atom cell is reused!
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-17
+
+
+      2.3.2.  string and symbol predicates
+
+(boundp 's_name)
+
+     RETURNS: nil  if s_name is  unbound,  that  is  it  has
+              never  be  given  a  value.  If x_name has the
+              value g_val, then (nil . g_val) is returned.
+
+(alphalessp 'st_arg1 'st_arg2)
+
+     RETURNS: t iff the `name' of st_arg1 is  alphabetically
+              less  than the name of st_arg2. If st_arg is a
+              symbol then its `name' is its print name.   If
+              st_arg  is  a  string,  then its `name' is the
+              string itself.
+
+
+
+      2.3.3.  symbol and string accessing
+
+(symeval 's_arg)
+
+     RETURNS: the value of symbol s_arg.
+
+     NOTE: It is illegal to ask for the value of an  unbound
+           symbol.   This  function  has  the same effect as
+           _\be_\bv_\ba_\bl, but compiles into much more efficient code.
+
+(get_pname 's_arg)
+
+     RETURNS: the string which is the print name of s_arg.
+
+(plist 's_arg)
+
+     RETURNS: the property list of s_arg.
+
+(getd 's_arg)
+
+     RETURNS: the function definition of  s_arg  or  nil  if
+              there is no function definition.
+
+     NOTE: the function definition may turn  out  to  be  an
+           array header.
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-18
+
+
+(getchar 's_arg 'x_index)
+(nthchar 's_arg 'x_index)
+(getcharn 's_arg 'x_index)
+
+     RETURNS: the x_index_\bt_\bh character of the print  name  of
+              s_arg  or  nil  if  x_index  is less than 1 or
+              greater than the length of s_arg's print name.
+
+     NOTE: _\bg_\be_\bt_\bc_\bh_\ba_\br and _\bn_\bt_\bh_\bc_\bh_\ba_\br return a symbol with a single
+           character print name, _\bg_\be_\bt_\bc_\bh_\ba_\br_\bn returns the fixnum
+           representation of the character.
+
+(substring 'st_string 'x_index ['x_length])
+(substringn 'st_string 'x_index ['x_length])
+
+     RETURNS: a string of length at most  x_length  starting
+              at x_index_\bt_\bh character in the string.
+
+     NOTE: If x_length is not given, all of  the  characters
+           for   x_index  to  the  end  of  the  string  are
+           returned.  If  x_index  is  negative  the  string
+           begins  at  the x_index_\bt_\bh character from the end.
+           If x_index is out of bounds, nil is returned.
+
+     NOTE: _\bs_\bu_\bb_\bs_\bt_\br_\bi_\bn_\bg returns a list of  symbols,  _\bs_\bu_\bb_\bs_\bt_\br_\bi_\bn_\bg_\bn
+           returns  a  list  of  fixnums.   If _\bs_\bu_\bb_\bs_\bt_\br_\bi_\bn_\bg_\bn is
+           given a 0 x_length argument then a single  fixnum
+           which is the x_index_\bt_\bh character is returned.
+
+
+
+      2.3.4.  symbol and string manipulation
+
+(set 's_arg1 'g_arg2)
+
+     RETURNS: g_arg2.
+
+     SIDE EFFECT: the value of s_arg1 is set to g_arg2.
+
+(setq s_atm1 'g_val1 [ s_atm2 'g_val2 ... ... ])
+
+     WHERE:   the arguments are  pairs  of  atom  names  and
+              expressions.
+
+     RETURNS: the last g_val_\bi.
+
+     SIDE EFFECT: each s_atm_\bi  is  set  to  have  the  value
+                  g_val_\bi.
+
+     NOTE: _\bs_\be_\bt evaluates all of its arguments, _\bs_\be_\bt_\bq does not
+           evaluate the s_atm_\bi.
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-19
+
+
+(desetq sl_pattern1 'g_exp1 [... ...])
+
+     RETURNS: g_expn
+
+     SIDE EFFECT: This  acts  just  like  _\bs_\be_\bt_\bq  if  all  the
+                  sl_pattern_\bi  are  symbols.  If sl_pattern_\bi
+                  is a list then it   is  a  template  which
+                  should  have  the same structure as g_exp_\bi
+                  The symbols in sl_pattern are assigned  to
+                  the corresponding parts of g_exp.
+
+     EXAMPLE: (_\bd_\be_\bs_\be_\bt_\bq (_\ba _\bb (_\bc . _\bd)) '(_\b1 _\b2 (_\b3 _\b4 _\b5)))
+              sets a to 1, b to 2, c to 3, and d to (4 5).
+
+
+(setplist 's_atm 'l_plist)
+
+     RETURNS: l_plist.
+
+     SIDE EFFECT: the property  list  of  s_atm  is  set  to
+                  l_plist.
+
+(makunbound 's_arg)
+
+     RETURNS: s_arg
+
+     SIDE EFFECT: the value of s_arg is made `unbound'.   If
+                  the interpreter attempts to evaluate s_arg
+                  before it  is  again  given  a  value,  an
+                  unbound variable error will occur.
+
+(aexplode 's_arg)
+(explode 'g_arg)
+(aexplodec 's_arg)
+(explodec 'g_arg)
+(aexploden 's_arg)
+(exploden 'g_arg)
+
+     RETURNS: a list of the characters  used  to  print  out
+              s_arg or g_arg.
+
+     NOTE: The functions beginning  with  'a'  are  internal
+           functions  which are limited to symbol arguments.
+           The functions _\ba_\be_\bx_\bp_\bl_\bo_\bd_\be and _\be_\bx_\bp_\bl_\bo_\bd_\be return a  list
+           of  characters which _\bp_\br_\bi_\bn_\bt would use to print the
+           argument. These characters include all  necessary
+           escape   characters.    Functions  _\ba_\be_\bx_\bp_\bl_\bo_\bd_\be_\bc  and
+           _\be_\bx_\bp_\bl_\bo_\bd_\be_\bc return a list of characters which  _\bp_\ba_\bt_\bo_\bm
+           would  use  to print the argument (i.e. no escape
+           characters).  Functions  _\ba_\be_\bx_\bp_\bl_\bo_\bd_\be_\bn  and  _\be_\bx_\bp_\bl_\bo_\bd_\be_\bn
+           are similar to _\ba_\be_\bx_\bp_\bl_\bo_\bd_\be_\bc and _\be_\bx_\bp_\bl_\bo_\bd_\be_\bc except that
+           a list of fixnum equivalents  of  characters  are
+           returned.
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-20
+
+
+
+    ____________________________________________________
+
+    -> (_\bs_\be_\bt_\bq _\bx '|_\bq_\bu_\bo_\bt_\be _\bt_\bh_\bi_\bs _\b\| _\bo_\bk?|)
+    |quote this \| ok?|
+    -> (_\be_\bx_\bp_\bl_\bo_\bd_\be _\bx)
+    (q u o t e |\\| | | t h i s |\\| | | |\\| |\|| |\\| | | o k ?)
+    ; note that |\\| just means the single character: backslash.
+    ; and |\|| just means the single character: vertical bar
+    ; and | | means the single character: space
+
+    -> (_\be_\bx_\bp_\bl_\bo_\bd_\be_\bc _\bx)
+    (q u o t e | | t h i s | | |\|| | | o k ?)
+    -> (_\be_\bx_\bp_\bl_\bo_\bd_\be_\bn _\bx)
+    (113 117 111 116 101 32 116 104 105 115 32 124 32 111 107 63)
+    ____________________________________________________
+
+
+
+
+
+
+   2.4.  Vectors
+
+           See Chapter 9 for a discussion of vectors.   They
+      are  intermediate  in  efficiency  between  arrays and
+      hunks.
+
+
+
+      2.4.1.  vector creation
+
+(new-vector 'x_size ['g_fill ['g_prop]])
+
+     RETURNS: A vector of length x_size.  Each data entry is
+              initialized to g_fill, or to nil, if the argu-
+              ment g_fill is not present.  The vector's pro-
+              perty is set to g_prop, or to nil, by default.
+
+(new-vectori-byte 'x_size ['g_fill ['g_prop]])
+(new-vectori-word 'x_size ['g_fill ['g_prop]])
+(new-vectori-long 'x_size ['g_fill ['g_prop]])
+
+     RETURNS: A vectori with x_size  elements  in  it.   The
+              actual  memory requirement is two long words +
+              x_size*(n  bytes),  where  n  is  1  for  new-
+              vector-byte,  2  for new-vector-word, or 4 for
+              new-vectori-long.  Each data entry is initial-
+              ized  to  g_fill,  or to zero, if the argument
+              g_fill is not present.  The vector's  property
+              is set to g_prop, or nil, by default.
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-21
+
+
+     Vectors may be created by specifying  multiple  initial
+     values:
+
+(vector ['g_val0 'g_val1 ...])
+
+     RETURNS: a vector, with as many data elements as  there
+              are arguments.  It is quite possible to have a
+              vector with no data  elements.   The  vector's
+              property will be null.
+
+(vectori-byte ['x_val0 'x_val2 ...])
+(vectori-word ['x_val0 'x_val2 ...])
+(vectori-long ['x_val0 'x_val2 ...])
+
+     RETURNS: a vectori, with as many data elements as there
+              are  arguments.  The arguments are required to
+              be fixnums.  Only the low order byte  or  word
+              is  used  in  the  case  of  vectori-byte  and
+              vectori-word.  The vector's property  will  be
+              null.
+
+
+
+      2.4.2.  vector reference
+
+(vref 'v_vect 'x_index)
+(vrefi-byte 'V_vect 'x_bindex)
+(vrefi-word 'V_vect 'x_windex)
+(vrefi-long 'V_vect 'x_lindex)
+
+     RETURNS: the desired data element from a  vector.   The
+              indices  must  be  fixnums.  Indexing is zero-
+              based.  The vrefi functions  sign  extend  the
+              data.
+
+(vprop 'Vv_vect)
+
+     RETURNS: The Lisp property associated with a vector.
+
+(vget 'Vv_vect 'g_ind)
+
+     RETURNS: The value stored under g_ind if the Lisp  pro-
+              perty  associated  with 'Vv_vect is a disembo-
+              died property list.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-22
+
+
+(vsize 'Vv_vect)
+(vsize-byte 'V_vect)
+(vsize-word 'V_vect)
+
+     RETURNS: the number of data  elements  in  the  vector.
+              For  immediate-vectors,  the  functions vsize-
+              byte and vsize-word return the number of  data
+              elements,  if one thinks of the binary data as
+              being comprised of bytes or words.
+
+
+
+      2.4.3.  vector modfication
+
+(vset 'v_vect 'x_index 'g_val)
+(vseti-byte 'V_vect 'x_bindex 'x_val)
+(vseti-word 'V_vect 'x_windex 'x_val)
+(vseti-long 'V_vect 'x_lindex 'x_val)
+
+     RETURNS: the datum.
+
+     SIDE EFFECT: The indexed element of the vector  is  set
+                  to  the value.  As noted above, for vseti-
+                  word and vseti-byte,  the  index  is  con-
+                  strued  as  the number of the data element
+                  within the  vector.   It  is  not  a  byte
+                  address.   Also,  for those two functions,
+                  the low order byte or  word  of  x_val  is
+                  what is stored.
+
+(vsetprop 'Vv_vect 'g_value)
+
+     RETURNS: g_value.  This should be either a symbol or  a
+              disembodied  property list whose _\bc_\ba_\br is a sym-
+              bol identifying the type of the vector.
+
+     SIDE EFFECT: the property list of  Vv_vect  is  set  to
+                  g_value.
+
+(vputprop 'Vv_vect 'g_value 'g_ind)
+
+     RETURNS: g_value.
+
+     SIDE EFFECT: If the vector property  of  Vv_vect  is  a
+                  disembodied  property  list, then vputprop
+                  adds the value g_value under the indicator
+                  g_ind.  Otherwise, the old vector property
+                  is made the first element of the list.
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-23
+
+
+   2.5.  Arrays
+
+           See Chapter  9  for  a  complete  description  of
+      arrays.  Some of these functions are part of a Maclisp
+      array compatibility package, which represents only one
+      simple way of using the array structure of FRANZ LISP.
+
+
+
+      2.5.1.  array creation
+
+(marray 'g_data 's_access 'g_aux 'x_length 'x_delta)
+
+     RETURNS: an array type with the fields set up from  the
+              above  arguments  in  the  obvious  way  (see
+              1.2.10).
+
+(*array 's_name 's_type 'x_dim1 ... 'x_dim_\bn)
+(array s_name s_type x_dim1 ... x_dim_\bn)
+
+     WHERE:   s_type may be one of t, nil,  fixnum,  flonum,
+              fixnum-block and flonum-block.
+
+     RETURNS: an array of type s_type with n  dimensions  of
+              extents given by the x_dim_\bi.
+
+     SIDE EFFECT: If s_name is non nil, the function defini-
+                  tion  of s_name is set to the array struc-
+                  ture returned.
+
+     NOTE: These  functions  create  a  Maclisp   compatible
+           array.  In FRANZ LISP arrays of type t, nil, fix-
+           num and flonum are equivalent and the elements of
+           these  arrays  can  be  any  type of lisp object.
+           Fixnum-block and  flonum-block  arrays  are  res-
+           tricted  to  fixnums and flonums respectively and
+           are used mainly to communicate with foreign func-
+           tions (see 8.5).
+
+     NOTE: *_\ba_\br_\br_\ba_\by evaluates its arguments, _\ba_\br_\br_\ba_\by does not.
+
+
+
+      2.5.2.  array predicate
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-24
+
+
+(arrayp 'g_arg)
+
+     RETURNS: t iff g_arg is of type array.
+
+
+
+      2.5.3.  array accessors
+
+
+(getaccess 'a_array)
+(getaux 'a_array)
+(getdelta 'a_array)
+(getdata 'a_array)
+(getlength 'a_array)
+
+     RETURNS: the field of the array object a_array given by
+              the function name.
+
+(arrayref 'a_name 'x_ind)
+
+     RETURNS: the  x_ind_\bt_\bh  element  of  the  array   object
+              a_name.  x_ind of zero accesses the first ele-
+              ment.
+
+     NOTE: _\ba_\br_\br_\ba_\by_\br_\be_\bf uses the data, length and  delta  fields
+           of a_name to determine which object to return.
+
+(arraycall s_type 'as_array 'x_ind1 ... )
+
+     RETURNS: the element selected by  the indicies from the
+              array a_array of type s_type.
+
+     NOTE: If as_array is a symbol then the function binding
+           of this symbol should contain an array object.
+           s_type is ignored by _\ba_\br_\br_\ba_\by_\bc_\ba_\bl_\bl  but  is  included
+           for compatibility with Maclisp.
+
+(arraydims 's_name)
+
+     RETURNS: a list of the type and  bounds  of  the  array
+              s_name.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-25
+
+
+(listarray 'sa_array ['x_elements])
+
+     RETURNS: a  list  of  all  of  the  elements  in  array
+              sa_array.   If  x_elements is given, then only
+              the first x_elements are returned.
+
+
+
+    ____________________________________________________
+
+    ; We will create a 3 by 4 array of general lisp objects
+    -> (_\ba_\br_\br_\ba_\by _\be_\br_\bn_\bi_\be _\bt _\b3 _\b4)
+    array[12]
+
+    ; the array header is stored in the function definition slot of the
+    ; symbol ernie
+    -> (_\ba_\br_\br_\ba_\by_\bp (_\bg_\be_\bt_\bd '_\be_\br_\bn_\bi_\be))
+    t
+    -> (_\ba_\br_\br_\ba_\by_\bd_\bi_\bm_\bs (_\bg_\be_\bt_\bd '_\be_\br_\bn_\bi_\be))
+    (t 3 4)
+
+    ; store in ernie[2][2] the list (test list)
+    -> (_\bs_\bt_\bo_\br_\be (_\be_\br_\bn_\bi_\be _\b2 _\b2) '(_\bt_\be_\bs_\bt _\bl_\bi_\bs_\bt))
+    (test list)
+
+    ; check to see if it is there
+    -> (_\be_\br_\bn_\bi_\be _\b2 _\b2)
+    (test list)
+
+    ; now use the low level function _\ba_\br_\br_\ba_\by_\br_\be_\bf to find the same element
+    ; arrays are 0 based and row-major (the last subscript varies the fastest)
+    ; thus element [2][2] is the 10th element , (starting at 0).
+    -> (_\ba_\br_\br_\ba_\by_\br_\be_\bf (_\bg_\be_\bt_\bd '_\be_\br_\bn_\bi_\be) _\b1_\b0)
+    (ptr to)(test list)    ; the result is a value cell (thus the (ptr to))
+    ____________________________________________________
+
+
+
+
+
+
+      2.5.4.  array manipulation
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-26
+
+
+(putaccess 'a_array 'su_func)
+(putaux 'a_array 'g_aux)
+(putdata 'a_array 'g_arg)
+(putdelta 'a_array 'x_delta)
+(putlength 'a_array 'x_length)
+
+     RETURNS: the second argument to the function.
+
+     SIDE EFFECT: The field of the array object given by the
+                  function  name  is  replaced by the second
+                  argument to the function.
+
+(store 'l_arexp 'g_val)
+
+     WHERE:   l_arexp is an expression which  references  an
+              array element.
+
+     RETURNS: g_val
+
+     SIDE EFFECT: the array location which contains the ele-
+                  ment  which  l_arexp references is changed
+                  to contain g_val.
+
+(fillarray 's_array 'l_itms)
+
+     RETURNS: s_array
+
+     SIDE EFFECT: the array s_array is filled with  elements
+                  from l_itms.  If there are not enough ele-
+                  ments in l_itms to fill the entire  array,
+                  then the last element of l_itms is used to
+                  fill the remaining parts of the array.
+
+
+
+   2.6.  Hunks
+
+           Hunks are  vector-like  objects  whose  size  can
+      range  from  1  to 128 elements.  Internally hunks are
+      allocated in sizes which are powers of 2.  In order to
+      create  hunks  of  a  given size, a hunk with at least
+      that many elements is allocated  and  a  distinguished
+      symbol   EMPTY   is   placed  in  those  elements  not
+      requested.  Most hunk  functions  respect  those  dis-
+      tinguished  symbols,  but  there are two (*_\bm_\ba_\bk_\bh_\bu_\bn_\bk and
+      *_\br_\bp_\bl_\ba_\bc_\bx) which will overwrite the  distinguished  sym-
+      bol.
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-27
+
+
+      2.6.1.  hunk creation
+
+(hunk 'g_val1 ['g_val2 ... 'g_val_\bn])
+
+     RETURNS: a hunk of length n whose elements are initial-
+              ized to the g_val_\bi.
+
+     NOTE: the maximum size of a hunk is 128.
+
+     EXAMPLE: (_\bh_\bu_\bn_\bk _\b4 '_\bs_\bh_\ba_\br_\bp '_\bk_\be_\by_\bs) = {4 sharp keys}
+
+(makhunk 'xl_arg)
+
+     RETURNS: a hunk of length  xl_arg  initialized  to  all
+              nils  if  xl_arg  is a fixnum.  If xl_arg is a
+              list,  then  we  return   a   hunk   of   size
+              (_\bl_\be_\bn_\bg_\bt_\bh '_\bx_\bl__\ba_\br_\bg)  initialized  to the elements
+              in xl_arg.
+
+     NOTE: (_\bm_\ba_\bk_\bh_\bu_\bn_\bk '(_\ba _\bb _\bc))     is      equivalent      to
+           (_\bh_\bu_\bn_\bk '_\ba '_\bb '_\bc).
+
+     EXAMPLE: (_\bm_\ba_\bk_\bh_\bu_\bn_\bk _\b4) = {_\bn_\bi_\bl _\bn_\bi_\bl _\bn_\bi_\bl _\bn_\bi_\bl}
+
+(*makhunk 'x_arg)
+
+     RETURNS: a hunk of size 2[x_arg] initialized to EMPTY.
+
+     NOTE: This is only to be used by such functions as _\bh_\bu_\bn_\bk
+           and _\bm_\ba_\bk_\bh_\bu_\bn_\bk which create and initialize hunks for
+           users.
+
+
+
+      2.6.2.  hunk accessor
+
+(cxr 'x_ind 'h_hunk)
+
+     RETURNS: element x_ind (starting at 0) of hunk h_hunk.
+
+(hunk-to-list 'h_hunk)
+
+     RETURNS: a list consisting of the elements of h_hunk.
+
+
+
+      2.6.3.  hunk manipulators
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-28
+
+
+(rplacx 'x_ind 'h_hunk 'g_val)
+(*rplacx 'x_ind 'h_hunk 'g_val)
+
+     RETURNS: h_hunk
+
+     SIDE EFFECT: Element x_ind (starting at 0) of h_hunk is
+                  set to g_val.
+
+     NOTE: _\br_\bp_\bl_\ba_\bc_\bx will not modify one of  the  distinguished
+           (EMPTY) elements whereas *_\br_\bp_\bl_\ba_\bc_\bx will.
+
+(hunksize 'h_arg)
+
+     RETURNS: the size of the hunk h_arg.
+
+     EXAMPLE: (_\bh_\bu_\bn_\bk_\bs_\bi_\bz_\be (_\bh_\bu_\bn_\bk _\b1 _\b2 _\b3)) = 3
+
+
+
+   2.7.  Bcds
+
+           A bcd object contains a pointer to compiled  code
+      and  to  the type of function object the compiled code
+      represents.
+
+(getdisc 'y_bcd)
+(getentry 'y_bcd)
+
+     RETURNS: the field of the bcd object given by the func-
+              tion name.
+
+(putdisc 'y_func 's_discipline)
+
+     RETURNS: s_discipline
+
+     SIDE EFFECT: Sets the discipline  field  of  y_func  to
+                  s_discipline.
+
+
+
+   2.8.  Structures
+
+           There are three common structures constructed out
+      of  list  cells: the assoc list, the property list and
+      the tconc list.  The functions below manipulate  these
+      structures.
+
+
+
+      2.8.1.  assoc list
+
+              An `assoc list' (or alist) is  a  common  lisp
+         data structure.  It has the form
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-29
+
+
+         ((key1 . value1) (key2 . value2) (key3 . value3) ... (keyn . valuen))
+
+(assoc 'g_arg1 'l_arg2)
+(assq 'g_arg1 'l_arg2)
+
+     RETURNS: the first top level element  of  l_arg2  whose
+              _\bc_\ba_\br is _\be_\bq_\bu_\ba_\bl (with _\ba_\bs_\bs_\bo_\bc) or _\be_\bq (with _\ba_\bs_\bs_\bq) to
+              g_arg1.
+
+     NOTE: Usually l_arg2 has an _\ba-_\bl_\bi_\bs_\bt structure and g_arg1
+           acts as key.
+
+(sassoc 'g_arg1 'l_arg2 'sl_func)
+
+     RETURNS: the                 result                  of
+              (_\bc_\bo_\bn_\bd ((_\ba_\bs_\bs_\bo_\bc '_\bg__\ba_\br_\bg '_\bl__\ba_\br_\bg_\b2) (_\ba_\bp_\bp_\bl_\by '_\bs_\bl__\bf_\bu_\bn_\bc _\bn_\bi_\bl)))
+
+     NOTE: sassoc is written as a macro.
+
+(sassq 'g_arg1 'l_arg2 'sl_func)
+
+     RETURNS: the                 result                  of
+              (_\bc_\bo_\bn_\bd ((_\ba_\bs_\bs_\bq '_\bg__\ba_\br_\bg '_\bl__\ba_\br_\bg_\b2) (_\ba_\bp_\bp_\bl_\by '_\bs_\bl__\bf_\bu_\bn_\bc _\bn_\bi_\bl)))
+
+     NOTE: sassq is written as a macro.
+
+
+
+    ____________________________________________________
+
+    ; _\ba_\bs_\bs_\bo_\bc or _\ba_\bs_\bs_\bq is given a key and an assoc list and returns
+    ; the key and value item if it exists, they differ only in how they test
+    ; for equality of the keys.
+
+    -> (_\bs_\be_\bt_\bq _\ba_\bl_\bi_\bs_\bt '((_\ba_\bl_\bp_\bh_\ba . _\ba) ( (_\bc_\bo_\bm_\bp_\bl_\be_\bx _\bk_\be_\by) . _\bb) (_\bj_\bu_\bn_\bk . _\bx)))
+    ((alpha . a) ((complex key) . b) (junk . x))
+
+    ; we should use _\ba_\bs_\bs_\bq when the key is an atom
+    -> (_\ba_\bs_\bs_\bq '_\ba_\bl_\bp_\bh_\ba _\ba_\bl_\bi_\bs_\bt)
+    (alpha . a)
+
+    ; but it may not work when the key is a list
+    -> (_\ba_\bs_\bs_\bq '(_\bc_\bo_\bm_\bp_\bl_\be_\bx _\bk_\be_\by) _\ba_\bl_\bi_\bs_\bt)
+    nil
+
+    ; however _\ba_\bs_\bs_\bo_\bc will always work
+    -> (_\ba_\bs_\bs_\bo_\bc '(_\bc_\bo_\bm_\bp_\bl_\be_\bx _\bk_\be_\by) _\ba_\bl_\bi_\bs_\bt)
+    ((complex key) . b)
+    ____________________________________________________
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-30
+
+
+(sublis 'l_alst 'l_exp)
+
+     WHERE:   l_alst is an _\ba-_\bl_\bi_\bs_\bt.
+
+     RETURNS: the list l_exp with every occurrence  of  key_\bi
+              replaced by val_\bi.
+
+     NOTE: new list structure is returned to prevent modifi-
+           cation  of l_exp.  When a substitution is made, a
+           copy of the value to substitute in is not made.
+
+
+
+      2.8.2.  property list
+
+              A property list  consists  of  an  alternating
+         sequence  of  keys and values.  Normally a property
+         list is stored on a symbol. A list is  a  'disembo-
+         died' property list if it contains an odd number of
+         elements, the first of which is ignored.
+
+(plist 's_name)
+
+     RETURNS: the property list of s_name.
+
+(setplist 's_atm 'l_plist)
+
+     RETURNS: l_plist.
+
+     SIDE EFFECT: the property  list  of  s_atm  is  set  to
+                  l_plist.
+
+
+(get 'ls_name 'g_ind)
+
+     RETURNS: the value under indicator g_ind  in  ls_name's
+              property list if ls_name is a symbol.
+
+     NOTE: If there is no indicator g_ind in ls_name's  pro-
+           perty list nil is returned.  If ls_name is a list
+           of an odd number of elements then it is a  disem-
+           bodied  property list. _\bg_\be_\bt searches a disembodied
+           property list by starting at its _\bc_\bd_\br, and compar-
+           ing every other element with g_ind, using _\be_\bq.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-31
+
+
+(getl 'ls_name 'l_indicators)
+
+     RETURNS: the property list  ls_name  beginning  at  the
+              first  indicator which is a member of the list
+              l_indicators, or nil if none of the indicators
+              in  l_indicators  are  on  ls_name's  property
+              list.
+
+     NOTE: If ls_name is a list, then it is assumed to be  a
+           disembodied property list.
+
+
+(putprop 'ls_name 'g_val 'g_ind)
+(defprop ls_name g_val g_ind)
+
+     RETURNS: g_val.
+
+     SIDE EFFECT: Adds to the property list of  ls_name  the
+                  value g_val under the indicator g_ind.
+
+     NOTE: _\bp_\bu_\bt_\bp_\br_\bo_\bp evaluates it arguments, _\bd_\be_\bf_\bp_\br_\bo_\bp does not.
+           ls_name  may  be a disembodied property list, see
+           _\bg_\be_\bt.
+
+(remprop 'ls_name 'g_ind)
+
+     RETURNS: the portion of  ls_name's property list begin-
+              ning  with  the  property  under the indicator
+              g_ind.  If there  is  no  g_ind  indicator  in
+              ls_name's plist, nil is returned.
+
+     SIDE EFFECT: the value under indicator g_ind and  g_ind
+                  itself  is  removed from the property list
+                  of ls_name.
+
+     NOTE: ls_name may be a disembodied property  list,  see
+           _\bg_\be_\bt.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-32
+
+
+
+    ____________________________________________________
+
+    -> (_\bp_\bu_\bt_\bp_\br_\bo_\bp '_\bx_\bl_\ba_\bt_\be '_\ba '_\ba_\bl_\bp_\bh_\ba)
+    a
+    -> (_\bp_\bu_\bt_\bp_\br_\bo_\bp '_\bx_\bl_\ba_\bt_\be '_\bb '_\bb_\be_\bt_\ba)
+    b
+    -> (_\bp_\bl_\bi_\bs_\bt '_\bx_\bl_\ba_\bt_\be)
+    (alpha a beta b)
+    -> (_\bg_\be_\bt '_\bx_\bl_\ba_\bt_\be '_\ba_\bl_\bp_\bh_\ba)
+    a
+    ; use of a disembodied property list:
+    -> (_\bg_\be_\bt '(_\bn_\bi_\bl _\bf_\ba_\bt_\be_\bm_\ba_\bn _\br_\bj_\bf _\bs_\bk_\bl_\bo_\bw_\be_\br _\bk_\bl_\bs _\bf_\bo_\bd_\be_\br_\ba_\br_\bo _\bj_\bk_\bf) '_\bs_\bk_\bl_\bo_\bw_\be_\br)
+    kls
+    ____________________________________________________
+
+
+
+
+
+
+      2.8.3.  tconc structure
+
+              A tconc structure is a special  type  of  list
+         designed to make it easy to add objects to the end.
+         It consists of a list cell whose _\bc_\ba_\br  points  to  a
+         list  of the elements added with _\bt_\bc_\bo_\bn_\bc or _\bl_\bc_\bo_\bn_\bc and
+         whose _\bc_\bd_\br points to the last list cell of the  list
+         pointed to by the _\bc_\ba_\br.
+
+(tconc 'l_ptr 'g_x)
+
+     WHERE:   l_ptr is a tconc structure.
+
+     RETURNS: l_ptr with g_x added to the end.
+
+(lconc 'l_ptr 'l_x)
+
+     WHERE:   l_ptr is a tconc structure.
+
+     RETURNS: l_ptr with the list l_x spliced in at the end.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-33
+
+
+
+    ____________________________________________________
+
+    ; A _\bt_\bc_\bo_\bn_\bc structure can be initialized in two  ways.
+    ; nil can be given to _\bt_\bc_\bo_\bn_\bc in which case _\bt_\bc_\bo_\bn_\bc will generate
+    ; a _\bt_\bc_\bo_\bn_\bc structure.
+
+    ->(_\bs_\be_\bt_\bq _\bf_\bo_\bo (_\bt_\bc_\bo_\bn_\bc _\bn_\bi_\bl _\b1))
+    ((1) 1)
+
+    ; Since _\bt_\bc_\bo_\bn_\bc destructively adds to
+    ; the list, you can now add to foo without using _\bs_\be_\bt_\bq again.
+
+    ->(_\bt_\bc_\bo_\bn_\bc _\bf_\bo_\bo _\b2)
+    ((1 2) 2)
+    ->_\bf_\bo_\bo
+    ((1 2) 2)
+
+    ; Another way to create a null  _\bt_\bc_\bo_\bn_\bc structure
+    ; is to use (_\bn_\bc_\bo_\bn_\bs _\bn_\bi_\bl).
+
+    ->(_\bs_\be_\bt_\bq _\bf_\bo_\bo (_\bn_\bc_\bo_\bn_\bs _\bn_\bi_\bl))
+    (nil)
+    ->(_\bt_\bc_\bo_\bn_\bc _\bf_\bo_\bo _\b1)
+    ((1) 1)
+
+    ; now see what _\bl_\bc_\bo_\bn_\bc can do
+    -> (_\bl_\bc_\bo_\bn_\bc _\bf_\bo_\bo _\bn_\bi_\bl)
+    ((1) 1)            ; no change
+    -> (_\bl_\bc_\bo_\bn_\bc _\bf_\bo_\bo '(_\b2 _\b3 _\b4))
+    ((1 2 3 4) 4)
+    ____________________________________________________
+
+
+
+
+
+
+      2.8.4.  fclosures
+
+              An  fclosure  is  a  functional  object  which
+         admits some data manipulations.  They are discussed
+         in 8.4.  Internally, they are constructed from vec-
+         tors.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-34
+
+
+(fclosure 'l_vars 'g_funobj)
+
+     WHERE:   l_vars is a list of variables, g_funobj is any
+              object that can be funcalled (including, fclo-
+              sures).
+
+     RETURNS: A vector which is the fclosure.
+
+(fclosure-alist 'v_fclosure)
+
+     RETURNS: An association list representing the variables
+              in  the  fclosure.   This is a snapshot of the
+              current state of the fclosure.  If  the  bind-
+              ings  in  the fclosure are changed, any previ-
+              ously  calculated  results  of  _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be-_\ba_\bl_\bi_\bs_\bt
+              will not change.
+
+(fclosure-function 'v_fclosure)
+
+     RETURNS: the functional object part of the fclosure.
+
+(fclosurep 'v_fclosure)
+
+     RETURNS: t iff the argument is an fclosure.
+
+(symeval-in-fclosure 'v_fclosure 's_symbol)
+
+     RETURNS: the current binding of a particular symbol  in
+              an fclosure.
+
+(set-in-fclosure 'v_fclosure 's_symbol 'g_newvalue)
+
+     RETURNS: g_newvalue.
+
+     SIDE EFFECT: The variable  s_symbol  is  bound  in  the
+                  fclosure to g_newvalue.
+
+
+
+   2.9.  Random functions
+
+           The following functions don't fall  into  any  of
+      the classifications above.
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-35
+
+
+(bcdad 's_funcname)
+
+     RETURNS: a fixnum which is the address in memory  where
+              the function s_funcname begins.  If s_funcname
+              is not a machine coded function (binary)  then
+              _\bb_\bc_\bd_\ba_\bd returns nil.
+
+(copy 'g_arg)
+
+     RETURNS: A structure _\be_\bq_\bu_\ba_\bl to g_arg but with  new  list
+              cells.
+
+(copyint* 'x_arg)
+
+     RETURNS: a fixnum with the same value as x_arg but in a
+              freshly allocated cell.
+
+(cpy1 'xvt_arg)
+
+     RETURNS: a new cell of the same type  as  xvt_arg  with
+              the same value as xvt_arg.
+
+(getaddress 's_entry1 's_binder1  'st_discipline1  [...  ...
+...])
+
+     RETURNS: the binary object which s_binder1's   function
+              field is set to.
+
+     NOTE: This looks in the running lisp's symbol table for
+           a symbol with the same name as s_entry_\bi.  It then
+           creates a binary object whose entry field  points
+           to    s_entry_\bi    and    whose    discipline   is
+           st_discipline_\bi.  This binary object is stored  in
+           the    function    field    of   s_binder_\bi.    If
+           st_discipline_\bi is nil, then "subroutine" is  used
+           by  default.  This is especially useful for _\bc_\bf_\ba_\bs_\bl
+           users.
+
+(macroexpand 'g_form)
+
+     RETURNS: g_form after all macros in it are expanded.
+
+     NOTE: This function will only  macroexpand  expressions
+           which  could  be  evaluated  and it does not know
+           about the special nlambdas such as _\bc_\bo_\bn_\bd  and  _\bd_\bo,
+           thus it misses many macro expansions.
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-36
+
+
+(ptr 'g_arg)
+
+     RETURNS: a value cell initialized to point to g_arg.
+
+(quote g_arg)
+
+     RETURNS: g_arg.
+
+     NOTE: the reader allows you to abbreviate  (quote  foo)
+           as 'foo.
+
+(kwote 'g_arg)
+
+     RETURNS:  (_\bl_\bi_\bs_\bt (_\bq_\bu_\bo_\bt_\be _\bq_\bu_\bo_\bt_\be) _\bg__\ba_\br_\bg).
+
+(replace 'g_arg1 'g_arg2)
+
+     WHERE:   g_arg1 and g_arg2 must be  the  same  type  of
+              lispval and not symbols or hunks.
+
+     RETURNS: g_arg2.
+
+     SIDE EFFECT: The effect of _\br_\be_\bp_\bl_\ba_\bc_\be is dependent on  the
+                  type  of  the  g_arg_\bi  although  one  will
+                  notice a similarity in  the  effects.   To
+                  understand what _\br_\be_\bp_\bl_\ba_\bc_\be does to fixnum and
+                  flonum arguments, you  must  first  under-
+                  stand  that  such  numbers  are `boxed' in
+                  FRANZ LISP.  What this means  is  that  if
+                  the  symbol  x  has a value 32412, then in
+                  memory the value  element  of  x's  symbol
+                  structure  contains the address of another
+                  word of memory (called a box)  with  32412
+                  in it.
+
+                  Thus, there are two ways of  changing  the
+                  value  of  x:  the  first is to change the
+                  value element of x's symbol  structure  to
+                  point to a word of memory with a different
+                  value.  The second way is  to  change  the
+                  value  in  the box which x points to.  The
+                  former method is used almost  all  of  the
+                  time,  the  latter is used very rarely and
+                  has the potential to  cause  great  confu-
+                  sion.   The function _\br_\be_\bp_\bl_\ba_\bc_\be allows you to
+                  do the latter, i.e.,  to  actually  change
+                  the value in the box.
+
+                  You should watch out for these situations.
+                  If  you  do  (_\bs_\be_\bt_\bq _\by _\bx), then both x and y
+                  will point to the same box.   If  you  now
+                  (_\br_\be_\bp_\bl_\ba_\bc_\be _\bx _\b1_\b2_\b3_\b4_\b5),  then  y will also have
+                  the value 12345.  And, in fact, there  may
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-37
+
+
+                  be many other pointers to that box.
+
+                  Another problem with replacing fixnums  is
+                  that  some  boxes are read-only.  The fix-
+                  nums between -1024 and 1023 are stored  in
+                  a  read-only  area and attempts to replace
+                  them will result  in  an  "Illegal  memory
+                  reference"  error  (see the description of
+                  _\bc_\bo_\bp_\by_\bi_\bn_\bt* for a way around this problem).
+
+                  For the other valid types, the  effect  of
+                  _\br_\be_\bp_\bl_\ba_\bc_\be is easy to understand.  The fields
+                  of g_val1's structure are made eq  to  the
+                  corresponding  fields  of  g_val2's struc-
+                  ture.  For example,  if  x   and   y  have
+                  lists   as   values  then  the  effect  of
+                  (_\br_\be_\bp_\bl_\ba_\bc_\be _\bx _\by)    is    the     same     as
+                  (_\br_\bp_\bl_\ba_\bc_\ba _\bx (_\bc_\ba_\br _\by)) and (_\br_\bp_\bl_\ba_\bc_\bd _\bx (_\bc_\bd_\br _\by)).
+
+(scons 'x_arg 'bs_rest)
+
+     WHERE:   bs_rest is a bignum or nil.
+
+     RETURNS: a bignum whose first bigit is x_arg and  whose
+              higher order bigits are bs_rest.
+
+(setf g_refexpr 'g_value)
+
+     NOTE: _\bs_\be_\bt_\bf is a generalization  of  setq.   Information
+           may  be  stored  by  binding variables, replacing
+           entries of arrays, and vectors, or being  put  on
+           property  lists,  among  others.  Setf will allow
+           the user to store data  into  some  location,  by
+           mentioning  the  operation  used  to refer to the
+           location.  Thus, the first argument may  be  par-
+           tially  evaluated,  but only to the extent needed
+           to calculate a reference.  _\bs_\be_\bt_\bf returns g_value.
+
+
+    ____________________________________________________
+
+      (setf x 3)        =  (setq x 3)
+      (setf (car x) 3)  = (rplaca x 3)
+      (setf (get foo 'bar) 3) = (putprop foo 3 'bar)
+      (setf (vref vector index) value) = (vset vector index value)
+    ____________________________________________________
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Data Structure Access                                   2-38
+
+
+(sort 'l_data 'u_comparefn)
+
+     RETURNS: a list of the elements of  l_data  ordered  by
+              the comparison function u_comparefn
+
+     SIDE EFFECT: the list l_data is  modified  rather  than
+                  allocate new storage.
+
+     NOTE: (_\bc_\bo_\bm_\bp_\ba_\br_\be_\bf_\bn '_\bg__\bx  '_\bg__\by)  should  return  something
+           non-nil  if  g-x can precede g_y in sorted order;
+           nil if g_y must precede g_x.  If  u_comparefn  is
+           nil, alphabetical order will be used.
+
+(sortcar 'l_list 'u_comparefn)
+
+     RETURNS: a list of the  elements  of  l_list  with  the
+              _\bc_\ba_\br's    ordered    by   the   sort   function
+              u_comparefn.
+
+     SIDE EFFECT: the list l_list is  modified  rather  than
+                  allocating new storage.
+
+     NOTE: Like _\bs_\bo_\br_\bt, if u_comparefn  is  nil,  alphabetical
+           order will be used.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/manual/ch4.r b/usr/src/ucb/lisp/lisplib/manual/ch4.r
new file mode 100644 (file)
index 0000000..c0a267f
--- /dev/null
@@ -0,0 +1,1725 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9
+
+
+
+
+
+
+
+
+
+
+                         CHAPTER  4
+
+
+                     Special Functions
+
+
+
+
+(and [g_arg1 ...])
+
+     RETURNS: the value of the last argument  if  all  argu-
+              ments  evaluate  to a non-nil value, otherwise
+              _\ba_\bn_\bd returns nil.  It returns t if there are no
+              arguments.
+
+     NOTE: the arguments are evaluated  left  to  right  and
+           evaluation  will cease with the first nil encoun-
+           tered
+
+(apply 'u_func 'l_args)
+
+     RETURNS: the result of applying function u_func to  the
+              arguments in the list l_args.
+
+     NOTE: If u_func is a lambda, then  the  (_\bl_\be_\bn_\bg_\bt_\bh _\bl__\ba_\br_\bg_\bs)
+           should  equal the number of formal parameters for
+           the u_func.  If u_func is  a  nlambda  or  macro,
+           then l_args is bound to the single formal parame-
+           ter.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9Special Functions                                        4-2
+
+
+
+
+
+
+
+Special Functions                                        4-1
+
+
+
+    ____________________________________________________
+
+    ; _\ba_\bd_\bd_\b1 is a lambda of 1 argument
+    -> (_\ba_\bp_\bp_\bl_\by '_\ba_\bd_\bd_\b1 '(_\b3))
+    4
+
+    ; we will define _\bp_\bl_\bu_\bs_\b1 as a macro which will be equivalent to _\ba_\bd_\bd_\b1
+    -> (_\bd_\be_\bf _\bp_\bl_\bu_\bs_\b1 (_\bm_\ba_\bc_\br_\bo (_\ba_\br_\bg) (_\bl_\bi_\bs_\bt '_\ba_\bd_\bd_\b1 (_\bc_\ba_\bd_\br _\ba_\br_\bg))))
+    plus1
+    -> (_\bp_\bl_\bu_\bs_\b1 _\b3)
+    4
+
+    ; now if we _\ba_\bp_\bp_\bl_\by a macro we obtain the form it changes to.
+    -> (_\ba_\bp_\bp_\bl_\by '_\bp_\bl_\bu_\bs_\b1 '(_\bp_\bl_\bu_\bs_\b1 _\b3))
+    (add1 3)
+
+    ; if we _\bf_\bu_\bn_\bc_\ba_\bl_\bl a macro however, the result of the macro is _\be_\bv_\ba_\bled
+    ; before it is returned.
+    -> (_\bf_\bu_\bn_\bc_\ba_\bl_\bl '_\bp_\bl_\bu_\bs_\b1 '(_\bp_\bl_\bu_\bs_\b1 _\b3))
+    4
+
+    ; for this particular macro, the _\bc_\ba_\br of the _\ba_\br_\bg is not checked
+    ; so that this too will work
+    -> (_\ba_\bp_\bp_\bl_\by '_\bp_\bl_\bu_\bs_\b1 '(_\bf_\bo_\bo _\b3))
+    (add1 3)
+
+    ____________________________________________________
+
+
+
+
+(arg ['x_numb])
+
+     RETURNS: if x_numb  is  specified  then  the  x_numb'_\bt_\bh
+              argument  to  the enclosing lexpr If x_numb is
+              not specified then this returns the number  of
+              arguments to the enclosing lexpr.
+
+     NOTE: it is an error to the interpreter  if  x_numb  is
+           given and out of range.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                        4-2
+
+
+(break [g_message ['g_pred]])
+
+     WHERE:   if g_message is not given it is assumed to  be
+              the null string, and if g_pred is not given it
+              is assumed to be t.
+
+     RETURNS: the value of (*_\bb_\br_\be_\ba_\bk '_\bg__\bp_\br_\be_\bd '_\bg__\bm_\be_\bs_\bs_\ba_\bg_\be)
+
+(*break 'g_pred 'g_message)
+
+     RETURNS: nil immediately if g_pred  is  nil,  else  the
+              value  of  the next (return 'value) expression
+              typed in at top level.
+
+     SIDE EFFECT: If the  predicate,  g_pred,  evaluates  to
+                  non-null, the lisp system stops and prints
+                  out `Break '  followed  by  g_message.  It
+                  then  enters a break loop which allows one
+                  to interactively debug a program.  To con-
+                  tinue  execution  from a break you can use
+                  the _\br_\be_\bt_\bu_\br_\bn  function.  to  return  to  top
+                  level  or another break level, you can use
+                  _\br_\be_\bt_\bb_\br_\bk or _\br_\be_\bs_\be_\bt.
+
+(caseq 'g_key-form l_clause1 ...)
+
+     WHERE:   l_clause_\bi is a list of the form  (g_comparator
+              ['g_form_\bi  ...]).  The comparators may be sym-
+              bols, small fixnums, a list of  small  fixnums
+              or symbols.
+
+     NOTE: The way caseq works is that it  evaluates  g_key-
+           form, yielding a value we will call the selector.
+           Each clause is examined  until  the  selector  is
+           found consistent with the comparator.  For a sym-
+           bol, or a fixnum, this means the two must be  _\be_\bq.
+           For  a list, this means that the selector must be
+           _\be_\bq to some element of the list.
+
+           The symbol t has special  semantics:  it  matches
+           anything,  and  consequently,  should be the last
+           comparator.  Then, having chosen a clause,  _\bc_\ba_\bs_\be_\bq
+           evaluates each form within that clause and
+
+     RETURNS: the value of the last form.  If no comparators
+              are matched, _\bc_\ba_\bs_\be_\bq returns nil.
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                        4-3
+
+
+
+    ____________________________________________________
+
+    Here are two ways of defining the same function:
+    ->(_\bd_\be_\bf_\bu_\bn _\bf_\ba_\bt_\be (_\bp_\be_\br_\bs_\bo_\bn_\bn_\ba)
+            (_\bc_\ba_\bs_\be_\bq _\bp_\be_\br_\bs_\bo_\bn_\bn_\ba
+              (_\bc_\bo_\bw '(_\bj_\bu_\bm_\bp_\be_\bd _\bo_\bv_\be_\br _\bt_\bh_\be _\bm_\bo_\bo_\bn))
+              (_\bc_\ba_\bt '(_\bp_\bl_\ba_\by_\be_\bd _\bn_\be_\br_\bo))
+              ((_\bd_\bi_\bs_\bh _\bs_\bp_\bo_\bo_\bn) '(_\br_\ba_\bn _\ba_\bw_\ba_\by _\bt_\bo_\bg_\be_\bt_\bh_\be_\br))
+              (_\bt '(_\bl_\bi_\bv_\be_\bd _\bh_\ba_\bp_\bp_\bi_\bl_\by _\be_\bv_\be_\br _\ba_\bf_\bt_\be_\br))))
+    fate
+    ->(_\bd_\be_\bf_\bu_\bn _\bf_\ba_\bt_\be (_\bp_\be_\br_\bs_\bo_\bn_\bn_\ba)
+            (_\bc_\bo_\bn_\bd
+                    ((_\be_\bq _\bp_\be_\br_\bs_\bo_\bn_\bn_\ba '_\bc_\bo_\bw) '(_\bj_\bu_\bm_\bp_\be_\bd _\bo_\bv_\be_\br _\bt_\bh_\be _\bm_\bo_\bo_\bn))
+                    ((_\be_\bq _\bp_\be_\br_\bs_\bo_\bn_\bn_\ba '_\bc_\ba_\bt) '(_\bp_\bl_\ba_\by_\be_\bd _\bn_\be_\br_\bo))
+                    ((_\bm_\be_\bm_\bq _\bp_\be_\br_\bs_\bo_\bn_\bn_\ba '(_\bd_\bi_\bs_\bh _\bs_\bp_\bo_\bo_\bn)) '(_\br_\ba_\bn _\ba_\bw_\ba_\by _\bt_\bo_\bg_\be_\bt_\bh_\be_\br))
+                    (_\bt '(_\bl_\bi_\bv_\be_\bd _\bh_\ba_\bp_\bp_\bi_\bl_\by _\be_\bv_\be_\br _\ba_\bf_\bt_\be_\br))))
+    fate
+    ____________________________________________________
+
+
+
+
+(catch g_exp [ls_tag])
+
+     WHERE:   if ls_tag is not given, it is  assumed  to  be
+              nil.
+
+     RETURNS: the result of (*_\bc_\ba_\bt_\bc_\bh '_\bl_\bs__\bt_\ba_\bg _\bg__\be_\bx_\bp)
+
+     NOTE: catch is defined as a macro.
+
+(*catch 'ls_tag g_exp)
+
+     WHERE:   ls_tag is either a symbol or a  list  of  sym-
+              bols.
+
+     RETURNS: the result of evaluating g_exp  or  the  value
+              thrown during the evaluation of g_exp.
+
+     SIDE EFFECT: this first sets up a `catch frame' on  the
+                  lisp  runtime  stack.   Then  it begins to
+                  evaluate g_exp.  If g_exp  evaluates  nor-
+                  mally,  its  value  is returned.  If, how-
+                  ever, a value is thrown during the evalua-
+                  tion of g_exp then this *catch will return
+                  with that value if one of these  cases  is
+                  true:
+
+     (1)  the tag thrown to is ls_tag
+
+     (2)  ls_tag is a list and the tag thrown to is a member
+          of this list
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                        4-4
+
+
+     (3)  ls_tag is nil.
+
+     NOTE: Errors are  implemented  as  a  special  kind  of
+           throw.   A  catch  with  no tag will not catch an
+           error but a catch whose tag  is  the  error  type
+           will  catch  that  type of error.  See Chapter 10
+           for more information.
+
+(comment [g_arg ...])
+
+     RETURNS: the symbol comment.
+
+     NOTE: This does absolutely nothing.
+
+(cond [l_clause1 ...])
+
+     RETURNS: the last value evaluated in the  first  clause
+              satisfied.   If  no clauses are satisfied then
+              nil is returned.
+
+     NOTE: This is  the  basic  conditional  `statement'  in
+           lisp.   The  clauses  are  processed from left to
+           right.   The  first  element  of  a   clause   is
+           evaluated.   If  it evaluated to a non-null value
+           then that clause is satisfied and  all  following
+           elements  of that clause are evaluated.  The last
+           value computed is returned as the  value  of  the
+           cond.  If there is just one element in the clause
+           then its value is returned.  If the first element
+           of a clause evaluates to nil, then the other ele-
+           ments of that clause are not  evaluated  and  the
+           system moves to the next clause.
+
+(cvttointlisp)
+
+     SIDE EFFECT: The reader is modified to conform with the
+                  Interlisp syntax.  The character % is made
+                  the escape character and special  meanings
+                  for  comma,  backquote  and  backslash are
+                  removed. Also the reader is told  to  con-
+                  vert upper case to lower case.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                        4-5
+
+
+(cvttofranzlisp)
+
+     SIDE EFFECT: The reader is  modified  to  conform  with
+                  franz's  default  syntax.   One  would run
+                  this function after  having  run  cvttoma-
+                  clisp, only.  Backslash is made the escape
+                  character, and  super-brackets  are  rein-
+                  stated.  The reader is reminded to distin-
+                  guish between upper and lower case.
+
+(cvttomaclisp)
+
+     SIDE EFFECT: The reader is  modified  to  conform  with
+                  Maclisp  syntax.   The character / is made
+                  the escape character and the special mean-
+                  ings for backslash, left and right bracket
+                  are removed.  The  reader  is  made  case-
+                  insensitive.
+
+(cvttoucilisp)
+
+     SIDE EFFECT: The reader is modified to conform with UCI
+                  Lisp  syntax.  The character / is made the
+                  escape character, tilde is made  the  com-
+                  ment character, exclamation point takes on
+                  the  unquote  function  normally  held  by
+                  comma,  and  backslash,  comma,  semicolon
+                  become normal characters.  Here  too,  the
+                  reader is made case-insensitive.
+
+(debug s_msg)
+
+     SIDE EFFECT: Enter  the  Fixit  package  described   in
+                  Chapter  15.   This  package allows you to
+                  examine the evaluation  stack  in  detail.
+                  To  leave the Fixit package type 'ok'.
+
+(debugging 'g_arg)
+
+     SIDE EFFECT: If g_arg is non-null,  Franz  unlinks  the
+                  transfer  tables, does a (*_\br_\bs_\be_\bt _\bt) to turn
+                  on  evaluation  monitoring  and  sets  the
+                  all-error  catcher  (ER%all)  to be _\bd_\be_\bb_\bu_\bg-
+                  _\be_\br_\br-_\bh_\ba_\bn_\bd_\bl_\be_\br.  If g_arg is nil, all of  the
+                  above changes are undone.
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                        4-6
+
+
+(declare [g_arg ...])
+
+     RETURNS: nil
+
+     NOTE: this is a no-op to the evaluator.  It has special
+           meaning to the compiler (see Chapter 12).
+
+(def s_name (s_type l_argl g_exp1 ...))
+
+     WHERE:   s_type is one of  lambda,  nlambda,  macro  or
+              lexpr.
+
+     RETURNS: s_name
+
+     SIDE EFFECT: This defines the function  s_name  to  the
+                  lisp  system.   If  s_type  is  nlambda or
+                  macro then the argument list  l_argl  must
+                  contain exactly one non-nil symbol.
+
+(defmacro s_name l_arg g_exp1 ...)
+(defcmacro s_name l_arg g_exp1 ...)
+
+     RETURNS: s_name
+
+     SIDE EFFECT: This defines the  macro  s_name.  _\bd_\be_\bf_\bm_\ba_\bc_\br_\bo
+                  makes  it  easy  to  write macros since it
+                  makes the syntax just like _\bd_\be_\bf_\bu_\bn.  Further
+                  information   on  _\bd_\be_\bf_\bm_\ba_\bc_\br_\bo  is  in  8.3.2.
+                  _\bd_\be_\bf_\bc_\bm_\ba_\bc_\br_\bo defines compiler-only macros, or
+                  cmacros.  A  cmacro  is stored on the pro-
+                  perty list of a symbol under the indicator
+                  cmacro.  Thus a function can have a normal
+                  definition and a cmacro  definition.   For
+                  an  example of the use of cmacros, see the
+                  definitions   of   nthcdr   and   nth   in
+                  /usr/lib/lisp/common2.l
+
+(defun s_name [s_mtype] ls_argl g_exp1 ... )
+
+     WHERE:   s_mtype is one of fexpr, expr, args or macro.
+
+     RETURNS: s_name
+
+     SIDE EFFECT: This defines the function s_name.
+
+     NOTE: this exists for Maclisp compatibility, it is just
+           a  macro  which changes the defun form to the def
+           form.   An  s_mtype  of  fexpr  is  converted  to
+           nlambda  and of expr to lambda. Macro remains the
+           same.  If ls_arg1 is a non-nil symbol,  then  the
+           type  is  assumed  to be lexpr and ls_arg1 is the
+           symbol which is bound to the number of args  when
+           the function is entered.
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                        4-7
+
+
+           For compatability with  the  Lisp  Machine  lisp,
+           there are three types of optional parameters that
+           can occur in ls_argl:   &_\bo_\bp_\bt_\bi_\bo_\bn_\ba_\bl  declares  that
+           the  following  symbols  are optional, and may or
+           may not appear in the argument list to the  func-
+           tion, &_\br_\be_\bs_\bt _\bs_\by_\bm_\bb_\bo_\bl declares that all forms in the
+           function call that are not accounted for by  pre-
+           vious  lambda bindings are to be assigned to _\bs_\by_\bm_\b-
+           _\bb_\bo_\bl, and &_\ba_\bu_\bx _\bf_\bo_\br_\bm_\b1 ... _\bf_\bo_\br_\bm_\bn declares  that  the
+           _\bf_\bo_\br_\bm_\bi  are either symbols, in which case they are
+           lambda bound to nil, or lists, in which case  the
+           first  element of the list is lambda bound to the
+           second, evaluated element.
+
+
+    ____________________________________________________
+
+    ; _\bd_\be_\bf and _\bd_\be_\bf_\bu_\bn here are used to define identical functions
+    ; you can decide for yourself which is easier to use.
+    -> (_\bd_\be_\bf _\ba_\bp_\bp_\be_\bn_\bd_\b1 (_\bl_\ba_\bm_\bb_\bd_\ba (_\bl_\bi_\bs _\be_\bx_\bt_\br_\ba) (_\ba_\bp_\bp_\be_\bn_\bd _\bl_\bi_\bs (_\bl_\bi_\bs_\bt _\be_\bx_\bt_\br_\ba))))
+    append1
+
+    -> (_\bd_\be_\bf_\bu_\bn _\ba_\bp_\bp_\be_\bn_\bd_\b1 (_\bl_\bi_\bs _\be_\bx_\bt_\br_\ba) (_\ba_\bp_\bp_\be_\bn_\bd _\bl_\bi_\bs (_\bl_\bi_\bs_\bt _\be_\bx_\bt_\br_\ba)))
+    append1
+
+    ; Using the & forms...
+    -> (_\bd_\be_\bf_\bu_\bn _\bt_\be_\bs_\bt (_\ba _\bb &_\bo_\bp_\bt_\bi_\bo_\bn_\ba_\bl _\bc &_\ba_\bu_\bx (_\br_\be_\bt_\bv_\ba_\bl _\b0) &_\br_\be_\bs_\bt _\bz)
+            (_\bi_\bf _\bc _\bt_\bh_\be_\bm (_\bm_\bs_\bg "_\bO_\bp_\bt_\bi_\bo_\bn_\ba_\bl _\ba_\br_\bg _\bp_\br_\be_\bs_\be_\bn_\bt" _\bN
+                            "_\bc _\bi_\bs " _\bc _\bN))
+            (_\bm_\bs_\bg "_\br_\be_\bs_\bt _\bi_\bs " _\bz _\bN
+                 "_\br_\be_\bt_\bv_\ba_\bl _\bi_\bs " _\br_\be_\bt_\bv_\ba_\bl _\bN))
+    test
+    -> (_\bt_\be_\bs_\bt _\b1 _\b2 _\b3 _\b4)
+    Optional arg present
+    c is 3
+    rest is (4)
+    retval is 0
+    ____________________________________________________
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                        4-8
+
+
+(defvar s_variable ['g_init])
+
+     RETURNS: s_variable.
+
+     NOTE: This form is put at the top level in files,  like
+           _\bd_\be_\bf_\bu_\bn.
+
+     SIDE EFFECT: This declares s_variable to be special. If
+                  g_init   is  present,  and  s_variable  is
+                  unbound  when  the  file   is   read   in,
+                  s_variable  will  be  set  to the value of
+                  g_init.  An advantage  of  `(defvar  foo)'
+                  over  `(declare (special foo))' is that if
+                  a file containing defvars  is  loaded  (or
+                  fasl'ed)  in during compilation, the vari-
+                  ables mentioned in the  defvar's  will  be
+                  declared  special.   The  only way to have
+                  that effect with `(declare (special foo))'
+                  is to _\bi_\bn_\bc_\bl_\bu_\bd_\be the file.
+
+(do l_vrbs l_test g_exp1 ...)
+
+     RETURNS: the last form in the cdr of l_test  evaluated,
+              or  a  value  explicitly  given  by  a  return
+              evaluated within the do body.
+
+     NOTE: This is the basic iteration form for FRANZ  LISP.
+           l_vrbs  is a list of zero or more var-init-repeat
+           forms.  A var-init-repeat form looks like:
+                (s_name [g_init [g_repeat]])
+           There  are  three  cases  depending  on  what  is
+           present  in the form.  If just s_name is present,
+           this means that when the do is entered, s_name is
+           lambda-bound  to nil and is never modified by the
+           system (though the program is certainly  free  to
+           modify    its    value).     If   the   form   is
+           (s_name 'g_init) then the only difference is that
+           s_name  is  lambda-bound  to  the value of g_init
+           instead of nil.  If g_repeat is also present then
+           s_name is lambda-bound to g_init when the loop is
+           entered and after each pass through the  do  body
+           s_name is  bound to the value of g_repeat.
+           l_test is either nil or has the form  of  a  cond
+           clause.   If  it  is nil then the do body will be
+           evaluated only once and the do will  return  nil.
+           Otherwise,  before  the  do body is evaluated the
+           car of l_test is evaluated and if the  result  is
+           non-null,  this  signals  an  end to the looping.
+           Then  the  rest  of  the  forms  in  l_test   are
+           evaluated  and  the  value  of  the  last  one is
+           returned as the value of the do.  If the  cdr  of
+           l_test  is nil, then nil is returned -- thus this
+           is not exactly like a cond clause.
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                        4-9
+
+
+           g_exp1 and those forms  which  follow  constitute
+           the  do  body.  A do body is like a prog body and
+           thus may have labels and one may  use  the  func-
+           tions go and return.
+           The sequence of evaluations is this:
+
+     (1)  the init forms are evaluated  left  to  right  and
+          stored in temporary locations.
+
+     (2)  Simultaneously all do variables are  lambda  bound
+          to the value of their init forms or nil.
+
+     (3)  If l_test is non-null, then the car  is  evaluated
+          and  if  it  is non-null, the rest of the forms in
+          l_test  are  evaluated  and  the  last  value   is
+          returned as the value of the do.
+
+     (4)  The forms in the do body  are  evaluated  left  to
+          right.
+
+     (5)  If l_test is nil the do function returns with  the
+          value nil.
+
+     (6)  The repeat forms are evaluated and saved  in  tem-
+          porary locations.
+
+     (7)  The variables with repeat forms are simultaneously
+          bound to the values of those forms.
+
+     (8)  Go to step 3.
+
+     NOTE: there is an alternate form of  do  which  can  be
+           used  when  there is only one do variable.  It is
+           described next.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-10
+
+
+
+    ____________________________________________________
+
+    ; this is  a simple function which numbers the elements of a list.
+    ; It uses a _\bd_\bo function with two local variables.
+    -> (_\bd_\be_\bf_\bu_\bn _\bp_\br_\bi_\bn_\bt_\be_\bm (_\bl_\bi_\bs)
+                 (_\bd_\bo ((_\bx_\bx _\bl_\bi_\bs (_\bc_\bd_\br _\bx_\bx))
+                      (_\bi _\b1 (_\b1+ _\bi)))
+                     ((_\bn_\bu_\bl_\bl _\bx_\bx) (_\bp_\ba_\bt_\bo_\bm "_\ba_\bl_\bl _\bd_\bo_\bn_\be") (_\bt_\be_\br_\bp_\br))
+                     (_\bp_\br_\bi_\bn_\bt _\bi)
+                     (_\bp_\ba_\bt_\bo_\bm ": ")
+                     (_\bp_\br_\bi_\bn_\bt (_\bc_\ba_\br _\bx_\bx))
+                     (_\bt_\be_\br_\bp_\br)))
+    printem
+    -> (_\bp_\br_\bi_\bn_\bt_\be_\bm '(_\ba _\bb _\bc _\bd))
+    1: a
+    2: b
+    3: c
+    4: d
+    all done
+    nil
+    ->
+    ____________________________________________________
+
+
+
+
+(do s_name g_init g_repeat g_test g_exp1 ...)
+
+     NOTE: this is another, less general,  form of  do.   It
+           is evaluated by:
+
+     (1)  evaluating g_init
+
+     (2)  lambda binding s_name to value of g_init
+
+     (3)  g_test is evaluated and if it is not  nil  the  do
+          function returns with nil.
+
+     (4)  the do body is evaluated beginning at g_exp1.
+
+     (5)  the repeat form is evaluated and stored in s_name.
+
+     (6)  go to step 3.
+
+     RETURNS: nil
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-11
+
+
+(environment [l_when1 l_what1 l_when2 l_what2 ...])
+(environment-maclisp [l_when1 l_what1 l_when2 l_what2 ...])
+(environment-lmlisp [l_when1 l_what1 l_when2 l_what2 ...])
+
+     WHERE:   the when's  are  a  subset  of  (eval  compile
+              load),  and  the symbols have the same meaning
+              as they do in 'eval-when'.
+
+              The what's may be
+                      (files file1 file2 ... fileN),
+              which insure that the named files are  loaded.
+              To  see  if  file_\bi  is  loaded, it looks for a
+              'version'  property  under  file_\bi's   property
+              list.   Thus  to prevent multiple loading, you
+              should put
+                      (putprop 'myfile t 'version),
+              at the end of myfile.l.
+
+              Another acceptible form for a what is
+              (syntax type)
+              Where type is either maclisp,  intlisp,  ucil-
+              isp,   franzlisp.    This   sets   the  syntax
+              correctly.
+
+              _\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt-_\bm_\ba_\bc_\bl_\bi_\bs_\bp sets  the  environment  to
+              that   which   `liszt   -m'   would  generate.
+              _\be_\bn_\bv_\bi_\br_\bo_\bn_\bm_\be_\bn_\bt-_\bl_\bm_\bl_\bi_\bs_\bp  sets up the  lisp  machine
+              environment.  This  is like maclisp but it has
+              additional  macros.   For  these   specialized
+              environments,  only the files clauses are use-
+              ful.           (environment-maclisp   (compile
+              eval) (files foo bar))
+
+(err ['s_value [nil]])
+
+     RETURNS: nothing (it never returns).
+
+     SIDE EFFECT: This causes an error and if this error  is
+                  caught  by an _\be_\br_\br_\bs_\be_\bt then that _\be_\br_\br_\bs_\be_\bt will
+                  return s_value instead  of  nil.   If  the
+                  second  arg  is given, then it must be nil
+                  (MAClisp compatibility).
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-12
+
+
+(error ['s_message1 ['s_message2]])
+
+     RETURNS: nothing (it never returns).
+
+     SIDE EFFECT: s_message1 and s_message2 are  _\bp_\ba_\bt_\bo_\bmed  if
+                  they  are  given  and  then  _\be_\br_\br is called
+                  (with  no  arguments),  which  causes   an
+                  error.
+
+(errset g_expr [s_flag])
+
+     RETURNS: a list of one  element,  which  is  the  value
+              resulting from evaluating g_expr.  If an error
+              occurs during the evaluation of  g_expr,  then
+              the locus of control will return to the _\be_\br_\br_\bs_\be_\bt
+              which will then return nil (unless  the  error
+              was  caused  by a call to _\be_\br_\br, with a non-null
+              argument).
+
+     SIDE EFFECT: S_flag  is  evaluated  before  g_expr   is
+                  evaluated. If s_flag is not given, then it
+                  is assumed to be t.  If  an  error  occurs
+                  during   the  evaluation  of  g_expr,  and
+                  s_flag evaluated to a non-null value, then
+                  the  error  message  associated  with  the
+                  error is printed before control returns to
+                  the errset.
+
+(eval 'g_val ['x_bind-pointer])
+
+     RETURNS: the result of evaluating g_val.
+
+     NOTE: The evaluator evaluates g_val in this way:
+           If g_val is a symbol, then the evaluator  returns
+           its  value.   If  g_val had never been assigned a
+           value, then this  causes  an  `Unbound  Variable'
+           error.   If  x_bind-pointer  is  given,  then the
+           variable  is  evaluated  with  respect  to   that
+           pointer  (see  _\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be  for  details  on  bind-
+           pointers).
+
+           If g_val is of type  value,  then  its  value  is
+           returned.   If  g_val  is  of any other type than
+           list, g_val is returned.
+
+           If g_val is a list object then g_val is either  a
+           function  call  or array reference.  Let g_car be
+           the  first  element  of  g_val.   We  continually
+           evaluate g_car until we end up with a symbol with
+           a non-null  function  binding  or  a  non-symbol.
+           Call what we end up with: g_func.
+
+           G_func must be one of three types:  list,  binary
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-13
+
+
+           or array.  If it is a list then the first element
+           of the list, which we shall call g_functype, must
+           be  either  lambda,  nlambda, macro or lexpr.  If
+           g_func is a binary, then its discipline, which we
+           shall call g_functype, is either lambda, nlambda,
+           macro or a string.  If g_func is  an  array  then
+           this  form  is evaluated specially, see Chapter 9
+           on arrays.  If g_func is a list or  binary,  then
+           g_functype  will  determine  how the arguments to
+           this function, the cdr of g_val,  are  processed.
+           If g_functype is a string, then this is a foreign
+           function call (see 8.5 for more details).
+
+           If g_functype is lambda or lexpr,  the  arguments
+           are  evaluated  (by calling _\be_\bv_\ba_\bl recursively) and
+           stacked.  If g_functype is nlambda then the argu-
+           ment  list  is  stacked.   If g_functype is macro
+           then the entire form, g_val is stacked.
+
+           Next, the formal variables are lambda bound.  The
+           formal  variables  are  the  cadr  of g_func.  If
+           g_functype is  nlambda,  lexpr  or  macro,  there
+           should  only  be one formal variable.  The values
+           on the stack are lambda bound to the formal vari-
+           ables  except  in  the case of a lexpr, where the
+           number of actual arguments is bound to the formal
+           variable.
+
+           After  the  binding  is  done,  the  function  is
+           invoked,  either by jumping to the entry point in
+           the case of a binary or by evaluating the list of
+           forms  beginning  at  cddr g_func.  The result of
+           this function invocation is returned as the value
+           of the call to eval.
+
+(evalframe 'x_pdlpointer)
+
+     RETURNS: an evalframe  descriptor  for  the  evaluation
+              frame    just    before    x_pdlpointer.    If
+              x_pdlpointer is nil, it returns the evaluation
+              frame  of  the  frame  just before the current
+              call to _\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be.
+
+     NOTE: An evalframe descriptor describes a call to _\be_\bv_\ba_\bl,
+           _\ba_\bp_\bp_\bl_\by or _\bf_\bu_\bn_\bc_\ba_\bl_\bl.  The form of the descriptor is
+           (_\bt_\by_\bp_\be  _\bp_\bd_\bl-_\bp_\bo_\bi_\bn_\bt_\be_\br  _\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn  _\bb_\bi_\bn_\bd-_\bp_\bo_\bi_\bn_\bt_\be_\br  _\bn_\bp-
+           _\bi_\bn_\bd_\be_\bx _\bl_\bb_\bo_\bt-_\bi_\bn_\bd_\be_\bx)
+           where type is `eval' if this describes a call  to
+           _\be_\bv_\ba_\bl  or  `apply'  if  this is a call to _\ba_\bp_\bp_\bl_\by or
+           _\bf_\bu_\bn_\bc_\ba_\bl_\bl.    pdl-pointer   is   a   number   which
+           describes this context. It can be passed to _\be_\bv_\ba_\bl_\b-
+           _\bf_\br_\ba_\bm_\be to obtain the next descriptor  and  can  be
+           passed  to  _\bf_\br_\be_\bt_\bu_\br_\bn  to  cause a return from this
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-14
+
+
+           context.  bind-pointer is the  size  of  variable
+           binding  stack  when  this  evaluation began. The
+           bind-pointer can be given as a second argument to
+           _\be_\bv_\ba_\bl  to  order to evaluate variables in the same
+           context as this  evaluation. If  type  is  `eval'
+           then  expression  will  have  the form (_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn-
+           _\bn_\ba_\bm_\be _\ba_\br_\bg_\b1 ...).  If type is `apply' then  expres-
+           sion    will    have    the    form    (_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn-
+           _\bn_\ba_\bm_\be (_\ba_\br_\bg_\b1 ...)).  np-index  and  lbot-index  are
+           pointers  into  the argument stack (also known as
+           the _\bn_\ba_\bm_\be_\bs_\bt_\ba_\bc_\bk array) at the time of call.   lbot-
+           index  points  to  the  first  argument, np-index
+           points one beyond the last argument.
+           In order for there to be enough  information  for
+           _\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be to return, you must call (*_\br_\bs_\be_\bt _\bt).
+
+     EXAMPLE: (_\bp_\br_\bo_\bg_\bn (_\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be _\bn_\bi_\bl))
+              returns  (_\be_\bv_\ba_\bl  _\b2_\b1_\b4_\b7_\b4_\b7_\b8_\b6_\b0_\b0  (_\bp_\br_\bo_\bg_\bn  (_\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be
+              _\bn_\bi_\bl)) _\b1 _\b8 _\b7)
+
+(evalhook 'g_form 'su_evalfunc ['su_funcallfunc])
+
+     RETURNS: the result of evaluating g_form  after  lambda
+              binding  `evalhook'  to su_evalfunc and, if it
+              is  given,  lambda  binding  `funcallhook'  to
+              su_funcallhook.
+
+     NOTE: As explained in 14.4, the function _\be_\bv_\ba_\bl may  pass
+           the  job  of  evaluating  a form to a user `hook'
+           function when  various  switches  are  set.   The
+           hook  function  normally  prints  the  form to be
+           evaluated on the terminal and then  evaluates  it
+           by  calling  _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk.   _\bE_\bv_\ba_\bl_\bh_\bo_\bo_\bk does the lambda
+           binding mentioned above and then  calls  _\be_\bv_\ba_\bl  to
+           evaluate  the  form  after  setting  an  internal
+           switch to tell _\be_\bv_\ba_\bl not to call the  user's  hook
+           function  just  this  one  time.  This allows the
+           evaluation process to advance one  step  and  yet
+           insure  that  further  calls  to  _\be_\bv_\ba_\bl will cause
+           traps to the hook  function  (if  su_evalfunc  is
+           non-null).
+           In order for  _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk  to  work,  (*_\br_\bs_\be_\bt _\bt)  and
+           (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk _\bt)  must  have been done previ-
+           ously.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-15
+
+
+(exec s_arg1 ...)
+
+     RETURNS: the result of forking and executing  the  com-
+              mand   named   by   concatenating  the  s_arg_\bi
+              together with spaces in between.
+
+(exece 's_fname ['l_args ['l_envir]])
+
+     RETURNS: the error code  from  the  system  if  it  was
+              unable  to  execute  the  command s_fname with
+              arguments l_args and with the environment  set
+              up  as specified in l_envir.  If this function
+              is successful, it will not return, instead the
+              lisp  system  will be overlaid by the new com-
+              mand.
+
+(freturn 'x_pdl-pointer 'g_retval)
+
+     RETURNS: g_retval from  the  context  given  by  x_pdl-
+              pointer.
+
+     NOTE: A  pdl-pointer  denotes  a   certain   expression
+           currently  being evaluated. The pdl-pointer for a
+           given expression can be obtained from _\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be.
+
+(frexp 'f_arg)
+
+     RETURNS: a  list  cell  (_\be_\bx_\bp_\bo_\bn_\be_\bn_\bt  .  _\bm_\ba_\bn_\bt_\bi_\bs_\bs_\ba)   which
+              represents the given flonum
+
+     NOTE: The exponent will be a fixnum, the mantissa a  56
+           bit bignum.  If you think of the the binary point
+           occurring right  after  the  high  order  bit  of
+           mantissa, then f_arg = 2[exponent] * mantissa.
+
+(funcall 'u_func ['g_arg1 ...])
+
+     RETURNS: the value of applying function u_func  to  the
+              arguments  g_arg_\bi  and  then  evaluating  that
+              result if u_func is a macro.
+
+     NOTE: If u_func is a macro or nlambda then there should
+           be only one g_arg.  _\bf_\bu_\bn_\bc_\ba_\bl_\bl is the function which
+           the evaluator uses to evaluate lists.  If _\bf_\bo_\bo  is
+           a    lambda    or    lexpr    or    array,   then
+           (_\bf_\bu_\bn_\bc_\ba_\bl_\bl '_\bf_\bo_\bo '_\ba '_\bb '_\bc)    is    equivalent    to
+           (_\bf_\bo_\bo '_\ba '_\bb '_\bc).    If   _\bf_\bo_\bo  is  a  nlambda  then
+           (_\bf_\bu_\bn_\bc_\ba_\bl_\bl '_\bf_\bo_\bo '(_\ba _\bb _\bc)) is equivalent to (_\bf_\bo_\bo _\ba _\bb
+           _\bc).    Finally,   if   _\bf_\bo_\bo   is   a   macro  then
+           (_\bf_\bu_\bn_\bc_\ba_\bl_\bl '_\bf_\bo_\bo '(_\bf_\bo_\bo _\ba _\bb _\bc))  is   equivalent   to
+           (_\bf_\bo_\bo _\ba _\bb _\bc).
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-16
+
+
+(funcallhook 'l_form 'su_funcallfunc ['su_evalfunc])
+
+     RETURNS: the result of _\bf_\bu_\bn_\bc_\ba_\bl_\bling the  (_\bc_\ba_\br _\bl__\bf_\bo_\br_\bm)  on
+              the   already   evaluated   arguments  in  the
+              (_\bc_\bd_\br _\bl__\bf_\bo_\br_\bm)  after   lambda   binding   `fun-
+              callhook'  to  su_funcallfunc  and,  if  it is
+              given,   lambda    binding    `evalhook'    to
+              su_evalhook.
+
+     NOTE: This function is designed to continue the evalua-
+           tion  process  with  as  little  work as possible
+           after a funcallhook trap has occurred. It is  for
+           this  reason  that the form of l_form is unortho-
+           dox: its _\bc_\ba_\br is the name of the function to  call
+           and  its  _\bc_\bd_\br  are  a  list of arguments to stack
+           (without evaluating  again)  before  calling  the
+           given function.  After stacking the arguments but
+           before calling _\bf_\bu_\bn_\bc_\ba_\bl_\bl an internal switch is  set
+           to  prevent  _\bf_\bu_\bn_\bc_\ba_\bl_\bl from passing the job of fun-
+           calling to su_funcallfunc.  If _\bf_\bu_\bn_\bc_\ba_\bl_\bl is  called
+           recursively   in   funcalling   l_form   and   if
+           su_funcallfunc is non-null, then the arguments to
+           _\bf_\bu_\bn_\bc_\ba_\bl_\bl  will actually be given to su_funcallfunc
+           (a lexpr) to be funcalled.
+           In order for  _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk  to  work,  (*_\br_\bs_\be_\bt _\bt)  and
+           (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk _\bt)  must  have been done previ-
+           ously.  A more detailed description  of  _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk
+           and _\bf_\bu_\bn_\bc_\ba_\bl_\bl_\bh_\bo_\bo_\bk is given in Chapter 14.
+
+(function u_func)
+
+     RETURNS: the function binding of u_func  if  it  is  an
+              symbol   with  a  function  binding  otherwise
+              u_func is returned.
+
+(getdisc 'y_func)
+
+     RETURNS: the discipline of the machine  coded  function
+              (either lambda, nlambda or macro).
+
+(go g_labexp)
+
+     WHERE:   g_labexp is either a symbol or an expression.
+
+     SIDE EFFECT: If g_labexp is an expression, that expres-
+                  sion  is  evaluated and should result in a
+                  symbol.  The locus  of  control  moves  to
+                  just  following the symbol g_labexp in the
+                  current prog or do body.
+
+     NOTE: this is only valid in the context of a prog or do
+           body.   The  interpreter  and compiler will allow
+           non-local _\bg_\bo's although the compiler won't  allow
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-17
+
+
+           a _\bg_\bo to leave a function body.  The compiler will
+           not allow g_labexp to be an expression.
+
+(if 'g_a 'g_b)
+(if 'g_a 'g_b 'g_c ...)
+(if 'g_a then  'g_b [...] [elseif 'g_c then 'g_d ...]  [else
+'g_e [...])
+(if 'g_a then  'g_b [...] [elseif 'g_c thenret]  [else  'g_d
+[...])
+
+     NOTE: The various forms of _\bi_\bf are intended to be a more
+           readable  conditional  statement,  to  be used in
+           place of _\bc_\bo_\bn_\bd.  There are two  varieties  of  _\bi_\bf,
+           with  keywords,  and  without.   The keyword-less
+           variety is inherited from common  Maclisp  usage.
+           A  keyword-less, two argument _\bi_\bf is equivalent to
+           a one-clause _\bc_\bo_\bn_\bd, i.e. (_\bc_\bo_\bn_\bd (a b)).   Any other
+           keyword-less  _\bi_\bf  must  have at least three argu-
+           ments.  The first two  arguments  are  the  first
+           clause  of the equivalent _\bc_\bo_\bn_\bd, and all remaining
+           arguments are shoved into a second clause  begin-
+           ning  with  t.   Thus,  the  second form of _\bi_\bf is
+           equivalent to
+                   (_\bc_\bo_\bn_\bd (a b) (t c ...)).
+
+           The keyword variety has the following grouping of
+           arguments:   a   predicate,  a  then-clause,  and
+           optional   else-clause.    The    predicate    is
+           evaluated,  and  if  the  result  is non-nil, the
+           then-clause  will  be  performed,  in  the  sense
+           described  below.  Otherwise, (i.e. the result of
+           the predicate evaluation was precisely nil),  the
+           else-clause will be performed.
+
+           Then-clauses will either consist entirely of  the
+           single  keyword  thenret,  or will start with the
+           keyword then, and be followed  by  at  least  one
+           general  expression.   (These general expressions
+           must not be one of the keywords.)  To  actuate  a
+           thenret  means to cease further evaluation of the
+           _\bi_\bf, and to return the value of the predicate just
+           calculated.  The performance of the longer clause
+           means to  evaluate  each  general  expression  in
+           turn, and then return the last value calculated.
+
+           The else-clause may begin with the  keyword  else
+           and  be  followed by at least one general expres-
+           sion.  The rendition of this clause is just  like
+           that  of a then-clause.  An else-clause may begin
+           alternatively with the  keyword  elseif,  and  be
+           followed  (recursively)  by  a  predicate,  then-
+           clause, and optional else-clause.  Evaluation  of
+           this  clause,  is  just evaluation of an _\bi_\bf-form,
+
+
+                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-18
+
+
+           with the same predicate, then- and else-clauses.
+
+(I-throw-err 'l_token)
+
+     WHERE:   l_token is the _\bc_\bd_\br of the value returned  from
+              a *_\bc_\ba_\bt_\bc_\bh with the tag ER%unwind-protect.
+
+     RETURNS: nothing (never returns in the current context)
+
+     SIDE EFFECT: The error or throw denoted by  l_token  is
+                  continued.
+
+     NOTE: This function is used to implement _\bu_\bn_\bw_\bi_\bn_\bd-_\bp_\br_\bo_\bt_\be_\bc_\bt
+           which allows the processing of a transfer of con-
+           trol though a certain context to be  interrupted,
+           a  user  function  to  be  executed  and than the
+           transfer of control to  continue.   The  form  of
+           l_token is either
+           (_\bt _\bt_\ba_\bg _\bv_\ba_\bl_\bu_\be) for a throw or
+           (_\bn_\bi_\bl _\bt_\by_\bp_\be _\bm_\be_\bs_\bs_\ba_\bg_\be _\bv_\ba_\bl_\br_\be_\bt  _\bc_\bo_\bn_\bt_\bu_\ba_\bb  _\bu_\bn_\bi_\bq_\bu_\be_\bi_\bd  [_\ba_\br_\bg
+           ...]) for an error.
+           This function is not to be used for  implementing
+           throws  or errors and is only documented here for
+           completeness.
+
+(let l_args g_exp1 ... g_exprn)
+
+     RETURNS: the result of evaluating  g_exprn  within  the
+              bindings given by l_args.
+
+     NOTE: l_args is either nil (in which case _\bl_\be_\bt  is  just
+           like  _\bp_\br_\bo_\bg_\bn)  or it is a list of binding objects.
+           A binding object is a  list  (_\bs_\by_\bm_\bb_\bo_\bl _\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn).
+           When  a _\bl_\be_\bt is entered all of the expressions are
+           evaluated and then simultaneously lambda bound to
+           the  corresponding  symbols.   In  effect,  a _\bl_\be_\bt
+           expression  is  just  like  a  lambda  expression
+           except  the  symbols and their initial values are
+           next to each other  which  makes  the  expression
+           easier  to  understand.   There  are  some  added
+           features to the _\bl_\be_\bt expression: A binding  object
+           can  just  be a symbol, in which case the expres-
+           sion corresponding to that symbol is `nil'.  If a
+           binding object is a list and the first element of
+           that list is another  list,  then  that  list  is
+           assumed  to be a binding template and _\bl_\be_\bt will do
+           a _\bd_\be_\bs_\be_\bt_\bq on it.
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-19
+
+
+(let* l_args g_exp1 ... g_expn)
+
+     RETURNS: the result of evaluating  g_exprn  within  the
+              bindings given by l_args.
+
+     NOTE: This is identical to _\bl_\be_\bt except  the  expressions
+           in  the  binding  list  l_args  are evaluated and
+           bound sequentially instead of in parallel.
+
+(lexpr-funcall 'g_function ['g_arg1 ...] 'l_argn)
+
+     NOTE: This is a cross between funcall and  apply.   The
+           last  argument,  must be a list (possibly empty).
+           The element of list arg are stack  and  then  the
+           function is funcalled.
+
+     EXAMPLE: (lexpr-funcall 'list 'a '(b c d)) is the  same
+              as
+               (funcall 'list 'a 'b 'c 'd)
+
+(listify 'x_count)
+
+     RETURNS: a list of x_count  of  the  arguments  to  the
+              current function (which must be a lexpr).
+
+     NOTE: normally  arguments   1   through   x_count   are
+           returned.  If x_count is negative then  a list of
+           last abs(x_count) arguments are returned.
+
+(map 'u_func 'l_arg1 ...)
+
+     RETURNS: l_arg1
+
+     NOTE: The function u_func is applied to successive sub-
+           lists  of  the  l_arg_\bi.  All sublists should have
+           the same length.
+
+(mapc 'u_func 'l_arg1 ...)
+
+     RETURNS: l_arg1.
+
+     NOTE: The function u_func is applied to successive ele-
+           ments  of  the  argument lists.  All of the lists
+           should have the same length.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-20
+
+
+(mapcan 'u_func 'l_arg1 ...)
+
+     RETURNS: nconc applied to the results of the functional
+              evaluations.
+
+     NOTE: The function u_func is applied to successive ele-
+           ments of the argument lists.  All sublists should
+           have the same length.
+
+(mapcar 'u_func 'l_arg1 ...)
+
+     RETURNS: a list of the values returned from  the  func-
+              tional application.
+
+     NOTE: the function u_func is applied to successive ele-
+           ments of the argument lists.  All sublists should
+           have the same length.
+
+(mapcon 'u_func 'l_arg1 ...)
+
+     RETURNS: nconc applied to the results of the functional
+              evaluation.
+
+     NOTE: the function u_func is applied to successive sub-
+           lists of the argument lists.  All sublists should
+           have the same length.
+
+(maplist 'u_func 'l_arg1 ...)
+
+     RETURNS: a  list  of  the  results  of  the  functional
+              evaluations.
+
+     NOTE: the function u_func is applied to successive sub-
+           lists  of  the  arguments  lists.   All  sublists
+           should have the same length.
+
+     Readers may find the following summary table useful  in
+     remembering  the  differences  between  the six mapping
+     functions:
+
+
+\e8     ________________________________________________________________
+                                      Value returned is
+
+                         l_arg1   list of results   _\bn_\bc_\bo_\bn_\bc of results
+\e7       Argument to
+       functional is
+\e8    ________________________________________________________________
+
+     elements of list    mapc        mapcar             mapcan
+
+         sublists        map         maplist            mapcon
+\e8    ________________________________________________________________
+\e7   |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+                     |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+                                                                   |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-21
+
+
+(mfunction t_entry 's_disc)
+
+     RETURNS: a lisp  object  of  type  binary  composed  of
+              t_entry and s_disc.
+
+     NOTE: t_entry is a pointer to the machine  code  for  a
+           function,  and  s_disc  is  the  discipline (e.g.
+           lambda).
+
+(oblist)
+
+     RETURNS: a list of all symbols on the oblist.
+
+(or [g_arg1 ... ])
+
+     RETURNS: the value of the first non-null  argument   or
+              nil if all arguments evaluate to nil.
+
+     NOTE: Evaluation proceeds left to right  and  stops  as
+           soon  as one of the arguments evaluates to a non-
+           null value.
+
+(prog l_vrbls g_exp1 ...)
+
+     RETURNS: the value explicitly given in a return form or
+              else  nil if no return is done by the time the
+              last g_exp_\bi is evaluated.
+
+     NOTE: the local variables are lambda bound to nil  then
+           the g_exp are evaluated from left to right.  This
+           is a prog body (obviously) and  this  means  than
+           any  symbols seen are not evaluated, instead they
+           are treated as  labels.   This  also  means  that
+           return's and go's are allowed.
+
+(prog1 'g_exp1 ['g_exp2 ...])
+
+     RETURNS: g_exp1
+
+(prog2 'g_exp1 'g_exp2 ['g_exp3 ...])
+
+     RETURNS: g_exp2
+
+     NOTE: the forms are evaluated from left  to  right  and
+           the value of g_exp2 is returned.
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-22
+
+
+(progn 'g_exp1 ['g_exp2 ...])
+
+     RETURNS: the last g_exp_\bi.
+
+(progv 'l_locv 'l_initv g_exp1 ...)
+
+     WHERE:   l_locv is a list of symbols and l_initv  is  a
+              list of expressions.
+
+     RETURNS: the value of the last g_exp_\bi evaluated.
+
+     NOTE: The expressions in  l_initv  are  evaluated  from
+           left  to  right and then lambda-bound to the sym-
+           bols in l_locv.  If there are too few expressions
+           in l_initv then the missing values are assumed to
+           be nil.  If there are  too  many  expressions  in
+           l_initv then the extra ones are ignored (although
+           they  are  evaluated).   Then  the   g_exp_\bi   are
+           evaluated  left to right.  The body of a progv is
+           like the body of a progn, it is _\bn_\bo_\bt a prog  body.
+           (C.f. _\bl_\be_\bt)
+
+(purcopy 'g_exp)
+
+     RETURNS: a copy of g_exp with new pure cells  allocated
+              wherever possible.
+
+     NOTE: pure space is never swept up by the garbage  col-
+           lector,  so  this  should only be done on expres-
+           sions which are not likely to become  garbage  in
+           the  future.   In  certain cases, data objects in
+           pure space become read-only after a _\bd_\bu_\bm_\bp_\bl_\bi_\bs_\bp  and
+           then  an attempt to modify the object will result
+           in an illegal memory reference.
+
+(purep 'g_exp)
+
+     RETURNS: t iff the object g_exp is in pure space.
+
+(putd 's_name 'u_func)
+
+     RETURNS: u_func
+
+     SIDE EFFECT: this sets the function binding  of  symbol
+                  s_name to u_func.
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-23
+
+
+(return ['g_val])
+
+     RETURNS: g_val (or nil if g_val is  not  present)  from
+              the enclosing prog or do body.
+
+     NOTE: this form is only valid in the context of a  prog
+           or do body.
+
+(selectq 'g_key-form [l_clause1 ...])
+
+     NOTE: This function is just  like  _\bc_\ba_\bs_\be_\bq  (see  above),
+           except  that  the  symbol  otherwise has the same
+           semantics as the symbol t, when used  as  a  com-
+           parator.
+
+(setarg 'x_argnum 'g_val)
+
+     WHERE:   x_argnum is greater than zero and less than or
+              equal to the number of arguments to the lexpr.
+
+     RETURNS: g_val
+
+     SIDE EFFECT: the lexpr's x_argnum'th argument is set to
+                  g-val.
+
+     NOTE: this can only be used within the body of a lexpr.
+
+(throw 'g_val [s_tag])
+
+     WHERE:   if s_tag is not given, it  is  assumed  to  be
+              nil.
+
+     RETURNS: the value of (*_\bt_\bh_\br_\bo_\bw '_\bs__\bt_\ba_\bg '_\bg__\bv_\ba_\bl).
+
+(*throw 's_tag 'g_val)
+
+     RETURNS: g_val from the first enclosing catch with  the
+              tag s_tag or with no tag at all.
+
+     NOTE: this is used in conjunction with *_\bc_\ba_\bt_\bc_\bh to  cause
+           a clean jump to an enclosing context.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
+
+
+
+
+Special Functions                                       4-24
+
+
+(unwind-protect g_protected [g_cleanup1 ...])
+
+     RETURNS: the result of evaluating g_protected.
+
+     NOTE: Normally g_protected is evaluated and  its  value
+           remembered, then the g_cleanup_\bi are evaluated and
+           finally  the  saved  value  of   g_protected   is
+           returned.    If   something  should  happen  when
+           evaluating g_protected which  causes  control  to
+           pass  through  g_protected   and thus through the
+           call to the unwind-protect, then  the  g_cleanup_\bi
+           will  still  be  evaluated.   This  is  useful if
+           g_protected does  something sensitive which  must
+           be  cleaned  up  whether  or not g_protected com-
+           pletes.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                      Printed: July 27, 1983
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/manual/ch6.r b/usr/src/ucb/lisp/lisplib/manual/ch6.r
new file mode 100644 (file)
index 0000000..775dc65
--- /dev/null
@@ -0,0 +1,1109 @@
+
+
+
+
+
+
+
+                         CHAPTER  6
+
+
+                      System Functions
+
+
+
+
+     This chapter describes the functions used  to  interact
+with  internal  components  of the Lisp system and operating
+system.
+
+(allocate 's_type 'x_pages)
+
+     WHERE:   s_type is one of the  FRANZ  LISP  data  types
+              described in 1.3.
+
+     RETURNS: x_pages.
+
+     SIDE EFFECT: FRANZ LISP attempts to allocate x_pages of
+                  type  s_type.   If there aren't x_pages of
+                  memory left, no space  will  be  allocated
+                  and an error will occur.  The storage that
+                  is allocated is not given to  the  caller,
+                  instead  it  is  added to the free storage
+                  list of s_type.  The functions _\bs_\be_\bg_\bm_\be_\bn_\bt and
+                  _\bs_\bm_\ba_\bl_\bl-_\bs_\be_\bg_\bm_\be_\bn_\bt  allocate blocks  of storage
+                  and return it to the caller.
+
+(argv 'x_argnumb)
+
+     RETURNS: a symbol whose pname is the x_argnumb_\bt_\bh  argu-
+              ment (starting at 0) on the command line which
+              invoked the current lisp.
+
+     NOTE: if x_argnumb is less than zero,  a  fixnum  whose
+           value  is  the number of arguments on the command
+           line is returned.  (_\ba_\br_\bg_\bv _\b0) returns the  name  of
+           the lisp you are running.
+
+(baktrace)
+
+     RETURNS: nil
+
+     SIDE EFFECT: the lisp runtime stack is examined and the
+                  name  of (most) of the functions currently
+                  in  execution  are  printed,  most  active
+                  first.
+
+     NOTE: this will occasionally miss the names of compiled
+           lisp  functions  due to incomplete information on
+           the stack.  If you  are  tracing  compiled  code,
+           then  _\bb_\ba_\bk_\bt_\br_\ba_\bc_\be  won't  be  able  to interpret the
+
+
+System Functions                                         6-1
+
+
+
+
+
+
+
+System Functions                                         6-2
+
+
+           stack unless  (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bt_\br_\ba_\bn_\bs_\bl_\bi_\bn_\bk _\bn_\bi_\bl)  was  done.
+           See  the  function  _\bs_\bh_\bo_\bw_\bs_\bt_\ba_\bc_\bk  for another way of
+           printing the lisp runtime stack.
+
+(boundp 's_name)
+
+     RETURNS: nil  if s_name is  unbound,  that  is  it  has
+              never  be  given  a  value.  If x_name has the
+              value g_val, then (nil . g_val) is returned.
+
+(chdir 's_path)
+
+     RETURNS: t iff the system call succeeds.
+
+     SIDE EFFECT: the current directory set to s_path. Among
+                  other things, this will affect the default
+                  location where the input/output  functions
+                  look for and create files.
+
+     NOTE: _\bc_\bh_\bd_\bi_\br follows the standard UNIX  conventions,  if
+           s_path  does  not begin with a slash, the default
+           path is changed to the current path  with  s_path
+           appended.   _\bC_\bh_\bd_\bi_\br  employs  tilde-expansion (dis-
+           cussed in Chapter 5).
+
+(command-line-args)
+
+     RETURNS: a list of the arguments typed on  the  command
+              line, either to the lisp interpreter, or saved
+              lisp dump, or application  compiled  with  the
+              autorun option (liszt -r).
+
+(deref 'x_addr)
+
+     RETURNS: The contents of x_addr, when thought of  as  a
+              longword memory location.
+
+     NOTE: This may be useful in constructing arguments to C
+           functions out of `dangerous' areas of memory.
+
+(dumplisp s_name)
+
+     RETURNS: nil
+
+     SIDE EFFECT: the current lisp is dumped  to  the  named
+                  file.   When  s_name is executed, you will
+                  be in a lisp in the same state as when the
+                  dumplisp was done.
+
+     NOTE: dumplisp will fail if one tries to write over the
+           current  running file. UNIX does not allow you to
+           modify the file you are running.
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                         6-3
+
+
+(eval-when l_time g_exp1 ...)
+
+     SIDE EFFECT: l_time may contain any combination of  the
+                  symbols  _\bl_\bo_\ba_\bd,  _\be_\bv_\ba_\bl,  and  _\bc_\bo_\bm_\bp_\bi_\bl_\be.   The
+                  effects of load and compile  is  discussed
+                  in  12.3.2.1 compiler.  If eval is present
+                  however,  this  simply  means   that   the
+                  expressions g_exp1 and so on are evaluated
+                  from  left  to  right.   If  eval  is  not
+                  present, the forms are not evaluated.
+
+(exit ['x_code])
+
+     RETURNS: nothing (it never returns).
+
+     SIDE EFFECT: the lisp system dies with exit code x_code
+                  or 0 if x_code is not specified.
+
+(fake 'x_addr)
+
+     RETURNS: the lisp object at address x_addr.
+
+     NOTE: This is intended to be used by  people  debugging
+           the lisp system.
+
+(fork)
+
+     RETURNS: nil to  the  child  process  and  the  process
+              number of the child to the parent.
+
+     SIDE EFFECT: A copy of the current lisp system is  made
+                  in  memory and both lisp systems now begin
+                  to  run.   This  function  can   be   used
+                  interactively   to  temporarily  save  the
+                  state of Lisp (as shown  below),  but  you
+                  must  be  careful  that  only  one  of the
+                  lisp's interacts with the  terminal  after
+                  the fork.  The _\bw_\ba_\bi_\bt function is useful for
+                  this.
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                         6-4
+
+
+
+    ____________________________________________________
+
+    -> (_\bs_\be_\bt_\bq _\bf_\bo_\bo '_\bb_\ba_\br)              ;; set a variable
+    bar
+    -> (_\bc_\bo_\bn_\bd ((_\bf_\bo_\br_\bk)(_\bw_\ba_\bi_\bt)))        ;; duplicate the lisp system and
+    nil                             ;; make the parent wait
+    -> _\bf_\bo_\bo                          ;; check the value of the variable
+    bar
+    -> (_\bs_\be_\bt_\bq _\bf_\bo_\bo '_\bb_\ba_\bz)              ;; give it a new value
+    baz
+    -> _\bf_\bo_\bo                          ;; make sure it worked
+    baz
+    -> (_\be_\bx_\bi_\bt)                       ;; exit the child
+    (5274 . 0)                      ;; the _\bw_\ba_\bi_\bt function returns this
+    -> _\bf_\bo_\bo                          ;; we check to make sure parent was
+    bar                             ;; not modified.
+    ____________________________________________________
+
+
+
+
+(gc)
+
+     RETURNS: nil
+
+     SIDE EFFECT: this causes a garbage collection.
+
+     NOTE: The function _\bg_\bc_\ba_\bf_\bt_\be_\br is not called  automatically
+           after  this function finishes.  Normally the user
+           doesn't have to call _\bg_\bc since garbage  collection
+           occurs automatically whenever internal free lists
+           are exhausted.
+
+(gcafter s_type)
+
+     WHERE:   s_type is one of the  FRANZ  LISP  data  types
+              listed in 1.3.
+
+     NOTE: this function is called by the garbage  collector
+           after  a  garbage  collection which was caused by
+           running out of data type s_type.   This  function
+           should  determine if more space need be allocated
+           and if so should allocate it.  There is a default
+           gcafter  function but users who want control over
+           space allocation can define their own -- but note
+           that it must be an nlambda.
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                         6-5
+
+
+(getenv 's_name)
+
+     RETURNS: a symbol whose pname is the value of s_name in
+              the   current  UNIX  environment.   If  s_name
+              doesn't exist in the  current  environment,  a
+              symbol with a null pname is returned.
+
+(hashtabstat)
+
+     RETURNS: a list of fixnums representing the  number  of
+              symbols in each bucket of the oblist.
+
+     NOTE: the oblist is stored a  hash  table  of  buckets.
+           Ideally there would be the same number of symbols
+           in each bucket.
+
+(help [sx_arg])
+
+     SIDE EFFECT: If sx_arg is a symbol then the portion  of
+                  this manual beginning with the description
+                  of sx_arg is printed on the terminal.   If
+                  sx_arg  is  a fixnum or the name of one of
+                  the appendicies, that chapter or  appendix
+                  is  printed  on the terminal.  If no argu-
+                  ment is provided, _\bh_\be_\bl_\bp prints the  options
+                  that it recognizes.  The program `more' is
+                  used to print the manual on the  terminal;
+                  it will stop after each page and will con-
+                  tinue after the space key is pressed.
+
+(include s_filename)
+
+     RETURNS: nil
+
+     SIDE EFFECT: The given  filename  is  _\bl_\bo_\ba_\bded  into  the
+                  lisp.
+
+     NOTE: this is similar to load except  the  argument  is
+           not  evaluated.   Include means something special
+           to the compiler.
+
+(include-if 'g_predicate s_filename)
+
+     RETURNS: nil
+
+     SIDE EFFECT: This has the same effect as  include,  but
+                  is  only actuated if the predicate is non-
+                  nil.
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                         6-6
+
+
+(includef 's_filename)
+
+     RETURNS: nil
+
+     SIDE EFFECT: this is the same  as  _\bi_\bn_\bc_\bl_\bu_\bd_\be  except  the
+                  argument is evaluated.
+
+(includef-if 'g_predicate s_filename)
+
+     RETURNS: nil
+
+     SIDE EFFECT: This has the same effect as includef,  but
+                  is  only actuated if the predicate is non-
+                  nil.
+
+(maknum 'g_arg)
+
+     RETURNS: the address of its argument converted  into  a
+              fixnum.
+
+(monitor ['xs_maxaddr])
+
+     RETURNS: t
+
+     SIDE EFFECT: If xs_maxaddr is t then profiling  of  the
+                  entire   lisp   system   is   begun.    If
+                  xs_maxaddr is a fixnum then  profiling  is
+                  done  only  up  to address xs_maxaddr.  If
+                  xs_maxaddr is not given, then profiling is
+                  stopped  and  the data obtained is written
+                  to the file  'mon.out'  where  it  can  be
+                  analyzed with the UNIX 'prof' program.
+
+     NOTE: this function only works if the lisp  system  has
+           been  compiled  in  a  special way, otherwise, an
+           error is invoked.
+
+(opval 's_arg ['g_newval])
+
+     RETURNS: the value associated  with  s_arg  before  the
+              call.
+
+     SIDE EFFECT: If g_newval is specified, the value  asso-
+                  ciated with s_arg is changed to g_newval.
+
+     NOTE: _\bo_\bp_\bv_\ba_\bl keeps track of storage allocation. If s_arg
+           is one of the data types then _\bo_\bp_\bv_\ba_\bl will return a
+           list of three fixnums representing the number  of
+           items  of  that  type in use, the number of pages
+           allocated and the number of items  of  that  type
+           per  page.  You  should  never  try to change the
+           value _\bo_\bp_\bv_\ba_\bl associates with  a  data  type  using
+           _\bo_\bp_\bv_\ba_\bl.
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                         6-7
+
+
+           If s_arg is _\bp_\ba_\bg_\be_\bl_\bi_\bm_\bi_\bt then _\bo_\bp_\bv_\ba_\bl will return (and
+           set  if  g_newval is given) the maximum amount of
+           lisp data pages it  will  allocate.   This  limit
+           should  remain small unless you know your program
+           requires lots of space as this limit  will  catch
+           programs   in  infinite  loops  which  gobble  up
+           memory.
+
+(*process 'st_command ['g_readp ['g_writep]])
+
+     RETURNS: either a fixnum if one argument is given, or a
+              list of two ports and a fixnum if two or three
+              arguments are given.
+
+     NOTE: *_\bp_\br_\bo_\bc_\be_\bs_\bs  starts  another  process   by   passing
+           st_command to the shell (it first tries /bin/csh,
+           then it tries /bin/sh if /bin/csh doesn't exist).
+           If  only one argument is given to *_\bp_\br_\bo_\bc_\be_\bs_\bs, *_\bp_\br_\bo_\b-
+           _\bc_\be_\bs_\bs waits for the new process to  die  and  then
+           returns  the  exit  code  of the new process.  If
+           more two or three arguments are  given,  *_\bp_\br_\bo_\bc_\be_\bs_\bs
+           starts the process and then returns a list which,
+           depending on the value of g_readp  and  g_writep,
+           may  contain  i/o ports for communcating with the
+           new process.  If g_writep  is  non-null,  then  a
+           port  will  be created which the lisp program can
+           use to send characters to the  new  process.   If
+           g_readp  is non-null, then a port will be created
+           which the lisp program can use to read characters
+           from  the  new  process.   The  value returned by
+           *_\bp_\br_\bo_\bc_\be_\bs_\bs is (readport writeport pid) where  read-
+           port and writeport are either nil or a port based
+           on the value of g_readp and g_writep.  Pid is the
+           process  id of the new process.  Since it is hard
+           to remember the order of  g_readp  and  g_writep,
+           the  functions *_\bp_\br_\bo_\bc_\be_\bs_\bs-_\bs_\be_\bn_\bd and *_\bp_\br_\bo_\bc_\be_\bs_\bs-_\br_\be_\bc_\be_\bi_\bv_\be
+           were written to perform the common functions.
+
+(*process-receive 'st_command)
+
+     RETURNS: a port which can be read.
+
+     SIDE EFFECT: The command st_command  is  given  to  the
+                  shell  and  it  is  started running in the
+                  background.  The output of that command is
+                  available   for   reading   via  the  port
+                  returned.  The input of the  command  pro-
+                  cess is set to /dev/null.
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                         6-8
+
+
+(*process-send 'st_command)
+
+     RETURNS: a port which can be written to.
+
+     SIDE EFFECT: The command st_command  is  given  to  the
+                  shell  and  it  is  started  runing in the
+                  background.  The lisp program can  provide
+                  input  for that command by sending charac-
+                  ters to the port returned  by  this  func-
+                  tion.   The  output of the command process
+                  is set to /dev/null.
+
+(process s_pgrm [s_frompipe s_topipe])
+
+     RETURNS: if the optional arguments are  not  present  a
+              fixnum  which  is  the  exit  code when s_prgm
+              dies.  If the optional arguments are  present,
+              it returns a fixnum which is the process id of
+              the child.
+
+     NOTE: This command is obsolete.   New  programs  should
+           use one of the *_\bp_\br_\bo_\bc_\be_\bs_\bs commands given above.
+
+     SIDE EFFECT: If s_frompipe and s_topipe are given, they
+                  are  bound  to ports which are pipes which
+                  direct characters from FRANZ LISP  to  the
+                  new process and to FRANZ LISP from the new
+                  process  respectively.   _\bP_\br_\bo_\bc_\be_\bs_\bs  forks  a
+                  process  named  s_prgm and waits for it to
+                  die iff there are no pipe arguments given.
+
+(ptime)
+
+     RETURNS: a list of  two  elements,  the  first  is  the
+              amount of processor time used by the lisp sys-
+              tem so far, the second is the amount  of  time
+              used by the garbage collector so far.
+
+     NOTE: the time is measured in those units used  by  the
+           _\bt_\bi_\bm_\be_\bs(2)  system call, usually 60_\bt_\bhs of a second.
+           The first number includes the second number.  The
+           amount  of time used by garbage collection is not
+           recorded until the first call to ptime.  This  is
+           done  to  prevent  overhead  when the user is not
+           interested in garbage collection times.
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                         6-9
+
+
+(reset)
+
+     SIDE EFFECT: the lisp runtime stack is cleared and  the
+                  system  restarts  at the top level by exe-
+                  cuting a (_\bf_\bu_\bn_\bc_\ba_\bl_\bl _\bt_\bo_\bp-_\bl_\be_\bv_\be_\bl _\bn_\bi_\bl).
+
+(restorelisp 's_name)
+
+     SIDE EFFECT: this  reads  in  file  s_name  (which  was
+                  created  by  _\bs_\ba_\bv_\be_\bl_\bi_\bs_\bp)  and  then  does  a
+                  (_\br_\be_\bs_\be_\bt).
+
+     NOTE: This is only used on VMS systems  where  _\bd_\bu_\bm_\bp_\bl_\bi_\bs_\bp
+           cannot be used.
+
+(retbrk ['x_level])
+
+     WHERE:   x_level is a small integer of either sign.
+
+     SIDE EFFECT: The default error handler keeps  a  notion
+                  of  the current level of the error caught.
+                  If x_level is negative, control is  thrown
+                  to  this default error handler whose level
+                  is that many less than the present, or  to
+                  _\bt_\bo_\bp-_\bl_\be_\bv_\be_\bl  if  there  aren't  enough.   If
+                  x_level is non-negative, control is passed
+                  to  the handler at that level.  If x_level
+                  is not present, the value -1 is  taken  by
+                  default.
+
+(*rset 'g_flag)
+
+     RETURNS: g_flag
+
+     SIDE EFFECT: If g_flag is non nil then the lisp  system
+                  will   maintain  extra  information  about
+                  calls to _\be_\bv_\ba_\bl and  _\bf_\bu_\bn_\bc_\ba_\bl_\bl.   This  record
+                  keeping slows down the evaluation but this
+                  is required  for the  functions  _\be_\bv_\ba_\bl_\bh_\bo_\bo_\bk,
+                  _\bf_\bu_\bn_\bc_\ba_\bl_\bl_\bh_\bo_\bo_\bk,  and  _\be_\bv_\ba_\bl_\bf_\br_\ba_\bm_\be  to  work. To
+                  debug  compiled  lisp  code  the  transfer
+                  tables       should      be      unlinked:
+                  (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bt_\br_\ba_\bn_\bs_\bl_\bi_\bn_\bk _\bn_\bi_\bl)
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                        6-10
+
+
+(savelisp 's_name)
+
+     RETURNS: t
+
+     SIDE EFFECT: the state of the Lisp system is  saved  in
+                  the  file  s_name.   It  can be read in by
+                  _\br_\be_\bs_\bt_\bo_\br_\be_\bl_\bi_\bs_\bp.
+
+     NOTE: This is only used on VMS systems  where  _\bd_\bu_\bm_\bp_\bl_\bi_\bs_\bp
+           cannot be used.
+
+(segment 's_type 'x_size)
+
+     WHERE:   s_type is one of the data types given in 1.3
+
+     RETURNS: a  segment  of  contiguous  lispvals  of  type
+              s_type.
+
+     NOTE: In reality, _\bs_\be_\bg_\bm_\be_\bn_\bt returns a new  data  cell  of
+           type  s_type  and  allocates space for x_size - 1
+           more s_type's beyond the one  returned.   _\bS_\be_\bg_\bm_\be_\bn_\bt
+           always  allocates  new  space  and does so in 512
+           byte chunks.  If you ask for 2  fixnums,  segment
+           will  actually  allocate 128 of them thus wasting
+           126 fixnums.  The  function  _\bs_\bm_\ba_\bl_\bl-_\bs_\be_\bg_\bm_\be_\bn_\bt  is  a
+           smarter  space allocator and should be used when-
+           ever possible.
+
+(shell)
+
+     RETURNS: the exit code of the shell when it dies.
+
+     SIDE EFFECT: this forks a new shell  and  returns  when
+                  the shell dies.
+
+(showstack)
+
+     RETURNS: nil
+
+     SIDE EFFECT: all  forms  currently  in  evaluation  are
+                  printed,  beginning  with the most recent.
+                  For compiled code the most that  showstack
+                  will  show is the function name and it may
+                  miss some functions.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                        6-11
+
+
+(signal 'x_signum 's_name)
+
+     RETURNS: nil if no previous call  to  signal  has  been
+              made, or the previously installed s_name.
+
+     SIDE EFFECT: this  declares  that  the  function  named
+                  s_name   will  handle  the  signal  number
+                  x_signum.  If s_name is nil, the signal is
+                  ignored.  Presently only four UNIX signals
+                  are caught, they and  their  numbers  are:
+                  Interrupt(2),    Floating    exception(8),
+                  Alarm(14), and Hang-up(1).
+
+(sizeof 'g_arg)
+
+     RETURNS: the number of  bytes  required  to  store  one
+              object of type g_arg, encoded as a fixnum.
+
+(small-segment 's_type 'x_cells)
+
+     WHERE:   s_type is one of fixnum, flonum and value.
+
+     RETURNS: a segment of  x_cells  data  objects  of  type
+              s_type.
+
+     SIDE EFFECT: This may  call  _\bs_\be_\bg_\bm_\be_\bn_\bt  to  allocate  new
+                  space  or  it  may  be  able  to  fill the
+                  request on a page already allocated.   The
+                  value returned by _\bs_\bm_\ba_\bl_\bl-_\bs_\be_\bg_\bm_\be_\bn_\bt is usually
+                  stored in the data  subpart  of  an  array
+                  object.
+
+(sstatus g_type g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: If  g_type  is  not  one  of  the  special
+                  sstatus  codes  described  in the next few
+                  pages this simply sets g_val as the  value
+                  of status type g_type in the system status
+                  property list.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                        6-12
+
+
+(sstatus appendmap g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: If g_val is non-null when _\bf_\ba_\bs_\bl is told  to
+                  create  a  load map, it will append to the
+                  file  name  given  in  the  _\bf_\ba_\bs_\bl  command,
+                  rather  than creating a new map file.  The
+                  initial value is nil.
+
+(sstatus automatic-reset g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: If g_val is non-null when an error  occurs
+                  which no one wants to handle, a _\br_\be_\bs_\be_\bt will
+                  be done instead of  entering  a  primitive
+                  internal break loop.  The initial value is
+                  t.
+
+(sstatus chainatom g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: If g_val is non nil and a _\bc_\ba_\br or _\bc_\bd_\br of  a
+                  symbol  is done, then nil will be returned
+                  instead of an error being signaled.   This
+                  only affects the interpreter, not the com-
+                  piler.  The initial value is nil.
+
+(sstatus dumpcore g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: If g_val is nil,  FRANZ  LISP  tells  UNIX
+                  that a segmentation violation or bus error
+                  should cause a core dump.  If g_val is non
+                  nil  then  FRANZ  LISP  will  catch  those
+                  errors and print a  message  advising  the
+                  user to reset.
+
+     NOTE: The initial value for this flag is nil, and  only
+           those  knowledgeable  of  the innards of the lisp
+           system should ever set this flag non nil.
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                        6-13
+
+
+(sstatus dumpmode x_val)
+
+     RETURNS: x_val
+
+     SIDE EFFECT: All subsequent _\bd_\bu_\bm_\bp_\bl_\bi_\bs_\bp's will be done  in
+                  mode  x_val.   x_val  may be either 413 or
+                  410 (decimal).
+
+     NOTE: the advantage of mode 413 is that the dumped Lisp
+           can  be demand paged in when first started, which
+           will make it start faster and disrupt other users
+           less.  The initial value is 413.
+
+(sstatus evalhook g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: When g_val is non nil,  this  enables  the
+                  evalhook  and  funcallhook  traps  in  the
+                  evaluator.  See 14.4 for more details.
+
+(sstatus feature g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: g_val is added  to  the  (_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be_\bs)
+                  list,
+
+(sstatus gcstrings g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: if g_val is non-null, and if  string  gar-
+                  bage  collection was enabled when the lisp
+                  system was compiled, string space will  be
+                  garbage collected.
+
+     NOTE: the default value for this is nil since  in  most
+           applications  garbage  collecting  strings  is  a
+           waste of time.
+
+(sstatus ignoreeof g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: If g_val is non-null when an end  of  file
+                  (CNTL-D  on UNIX) is typed to the standard
+                  top-level interpreter, it will be  ignored
+                  rather then cause the lisp system to exit.
+                  If the the standard input  is  a  file  or
+                  pipe  then this has no effect, an EOF will
+                  always cause lisp to  exit.   The  initial
+                  value is nil.
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                        6-14
+
+
+(sstatus nofeature g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: g_val is removed from the status  features
+                  list if it was present.
+
+(sstatus translink g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: If g_val is nil then all  transfer  tables
+                  are  cleared and further calls through the
+                  transfer table will  not  cause  the  fast
+                  links  to be set up.  If g_val is the sym-
+                  bol _\bo_\bn then all  possible  transfer  table
+                  entries  will  be linked and the flag will
+                  be set to cause fast links to  be  set  up
+                  dynamically.   Otherwise  all that is done
+                  is to set the flag to cause fast links  to
+                  be  set up dynamically.  The initial value
+                  is nil.
+
+     NOTE: For a discussion of transfer tables, see 12.8.
+
+(sstatus uctolc g_val)
+
+     RETURNS: g_val
+
+     SIDE EFFECT: If g_val is not  nil  then  all  unescaped
+                  capital  letters  in  symbols  read by the
+                  reader will be converted to lower case.
+
+     NOTE: This allows FRANZ LISP to be compatible with sin-
+           gle  case  lisp  systems (e.g. Maclisp, Interlisp
+           and UCILisp).
+
+(status g_code)
+
+     RETURNS: the value  associated  with  the  status  code
+              g_code  if  g_code  is  not one of the special
+              cases given below
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                        6-15
+
+
+(status ctime)
+
+     RETURNS: a symbol whose print name is the current  time
+              and date.
+
+     EXAMPLE: (_\bs_\bt_\ba_\bt_\bu_\bs _\bc_\bt_\bi_\bm_\be) = |Sun Jun 29 16:51:26 1980|
+
+     NOTE: This  has  been  made  obsolete  by  _\bt_\bi_\bm_\be-_\bs_\bt_\br_\bi_\bn_\bg,
+           described below.
+
+(status feature g_val)
+
+     RETURNS: t iff g_val is in the status features list.
+
+(status features)
+
+     RETURNS: the value of the features  code,  which  is  a
+              list  of  features  which  are present in this
+              system.    You   add   to   this   list   with
+              (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be '_\bg__\bv_\ba_\bl)  and  test if feature
+              g_feat         is         present         with
+              (_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be '_\bg__\bf_\be_\ba_\bt).
+
+(status isatty)
+
+     RETURNS: t iff the standard input is a terminal.
+
+(status localtime)
+
+     RETURNS: a list of  fixnums  representing  the  current
+              time.
+
+     EXAMPLE: (_\bs_\bt_\ba_\bt_\bu_\bs _\bl_\bo_\bc_\ba_\bl_\bt_\bi_\bm_\be) =  (3 51 13 31 6 81  5  211
+              1)
+              means 3_\br_\bd second, 51_\bs_\bt minute,  13_\bt_\bh  hour  (1
+              p.m), 31_\bs_\bt day, month 6 (0 = January), year 81
+              (0 = 1900), day of the  week  5  (0 = Sunday),
+              211_\bt_\bh  day  of  the  year and daylight savings
+              time is in effect.
+
+(status syntax s_char)
+
+     NOTE: This  function  should  not  be  used.   See  the
+           description  of  _\bg_\be_\bt_\bs_\by_\bn_\bt_\ba_\bx  (in  Chapter 7) for a
+           replacement.
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                        6-16
+
+
+(status undeffunc)
+
+     RETURNS: a list of all functions which  transfer  table
+              entries  point to but which are not defined at
+              this point.
+
+     NOTE: Some of the undefined functions listed  could  be
+           arrays which have yet to be created.
+
+(status version)
+
+     RETURNS: a string which is  the  current  lisp  version
+              name.
+
+     EXAMPLE: (_\bs_\bt_\ba_\bt_\bu_\bs _\bv_\be_\br_\bs_\bi_\bo_\bn) = "Franz Lisp, Opus 38.61"
+
+(syscall 'x_index ['xst_arg1 ...])
+
+     RETURNS: the result of issuing  the  UNIX  system  call
+              number x_index with arguments xst_arg_\bi.
+
+     NOTE: The UNIX system calls are described in section  2
+           of the UNIX Programmer's manual. If xst_arg_\bi is a
+           fixnum, then its value is passed as an  argument,
+           if  it  is  a symbol then its pname is passed and
+           finally if it is a string then the string  itself
+           is  passed  as an argument.  Some useful syscalls
+           are:
+           (_\bs_\by_\bs_\bc_\ba_\bl_\bl _\b2_\b0) returns process id.
+           (_\bs_\by_\bs_\bc_\ba_\bl_\bl _\b1_\b3) returns the number of seconds  since
+           Jan 1, 1970.
+           (_\bs_\by_\bs_\bc_\ba_\bl_\bl _\b1_\b0 '_\bf_\bo_\bo) will unlink (delete)  the  file
+           foo.
+
+(sys:access 'st_filename 'x_mode)
+(sys:chmod 'st_filename 'x_mode)
+(sys:gethostname)
+(sys:getpid)
+(sys:getpwnam 'st_username)
+(sys:link 'st_oldfilename 'st_newfilename)
+(sys:time)
+(sys:unlink 'st_filename)
+
+     NOTE: We have been warned that the actual  system  call
+           numbers  may  vary  among different UNIX systems.
+           Users concerned about portability may wish to use
+           this  group  of  functions.  Another advantage is
+           that tilde-expansion is performed on all filename
+           arguments.   These functions do what is described
+           in the system call section of your UNIX manual.
+
+           _\bs_\by_\bs:_\bg_\be_\bt_\bp_\bw_\bn_\ba_\bm_\be returns a vector  of  four  entries
+           from the password file, being the user name, user
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+System Functions                                        6-17
+
+
+           id, group id, and home directory.
+
+(time-string ['x_seconds])
+
+     RETURNS: an ascii string,  giving  the  time  and  date
+              which was x_seconds after UNIX's idea of crea-
+              tion (Midnight, Jan 1, 1970 GMT).  If no argu-
+              ment is given, time-string returns the current
+              date.  This supplants (_\bs_\bt_\ba_\bt_\bu_\bs _\bc_\bt_\bi_\bm_\be), and  may
+              be  used  to make the results of _\bf_\bi_\bl_\be_\bs_\bt_\ba_\bt more
+              intelligible.
+
+(top-level)
+
+     RETURNS: nothing (it never returns)
+
+     NOTE: This function is  the  top-level  read-eval-print
+           loop.   It  never  returns  any  value.  Its main
+           utility is that if you  redefine  it,  and  do  a
+           (reset)  then  the  redefined (top-level) is then
+           invoked.  The default top-level for Franz,  allow
+           one  to  specify  his  own  printer or reader, by
+           binding the symbols  top-level-printer  and  top-
+           level-reader.   One can let the default top-level
+           do most of the drudgery in catching _\br_\be_\bs_\be_\bt's,  and
+           reading  in  .lisprc files, by binding the symbol
+           user-top-level, to a routine that concerns itself
+           only with the read-eval-print loop.
+
+(wait)
+
+     RETURNS: a dotted pair (_\bp_\br_\bo_\bc_\be_\bs_\bs_\bi_\bd .  _\bs_\bt_\ba_\bt_\bu_\bs)  when  the
+              next child process dies.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/manual/ch8.r b/usr/src/ucb/lisp/lisplib/manual/ch8.r
new file mode 100644 (file)
index 0000000..424c695
--- /dev/null
@@ -0,0 +1,1324 @@
+
+
+
+
+
+
+
+                         CHAPTER  8
+
+
+              Functions, Fclosures, and Macros
+
+
+
+
+
+
+   8.1.  valid function objects
+
+           There are many different objects which can occupy
+      the  function field of a symbol object.  Table 8.1, on
+      the following page, shows all  of  the  possibilities,
+      how  to recognize them, and where to look for documen-
+      tation.
+
+
+
+   8.2.  functions
+
+           The basic Lisp function is the  lambda  function.
+      When a lambda function is called, the actual arguments
+      are evaluated from left to right and are  lambda-bound
+      to the formal parameters of the lambda function.
+
+           An nlambda function is usually used for functions
+      which  are  invoked  by  the  user at top level.  Some
+      built-in functions which evaluate their  arguments  in
+      special  ways  are  also  nlambdas (e.g _\bc_\bo_\bn_\bd, _\bd_\bo, _\bo_\br).
+      When an  nlambda  function  is  called,  the  list  of
+      unevaluated  arguments  is  lambda bound to the single
+      formal parameter of the nlambda function.
+
+           Some programmers will  use  an  nlambda  function
+      when  they  are  not  sure  how many arguments will be
+      passed.  Then, the first thing  the  nlambda  function
+      does  is  map  _\be_\bv_\ba_\bl over the list of unevaluated argu-
+      ments it has been passed.  This is usually  the  wrong
+      thing  to  do,  as it will not work compiled if any of
+      the arguments are local variables. The solution is  to
+      use  a  lexpr.   When  a lexpr function is called, the
+      arguments are evaluated and a fixnum  whose  value  is
+      the  number of arguments is lambda-bound to the single
+      formal parameter of the lexpr function.  The lexpr can
+      then access the arguments using the _\ba_\br_\bg function.
+
+           When a function is compiled, _\bs_\bp_\be_\bc_\bi_\ba_\bl declarations
+      may  be  needed to preserve its behavior.  An argument
+      is not lambda-bound to the name of  the  corresponding
+      formal parameter unless that formal parameter has been
+      declared _\bs_\bp_\be_\bc_\bi_\ba_\bl (see 12.3.2.2).
+
+
+Functions, Fclosures, and Macros                         8-1
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                         8-2
+
+
+
+
+
+\e8________________________________________________________________
+   informal name            object type          documentation
+\e8________________________________________________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b________________________________________________________________
+    interpreted            list with _\bc_\ba_\br              8.2
+  lambda function           _\be_\bq to lambda
+\e8________________________________________________________________
+    interpreted            list with _\bc_\ba_\br              8.2
+  nlambda function         _\be_\bq to nlambda
+\e8________________________________________________________________
+    interpreted            list with _\bc_\ba_\br              8.2
+   lexpr function           _\be_\bq to lexpr
+\e8________________________________________________________________
+    interpreted            list with _\bc_\ba_\br              8.3
+       macro                _\be_\bq to macro
+\e8________________________________________________________________
+      fclosure           vector with _\bv_\bp_\br_\bo_\bp            8.4
+                           _\be_\bq to fclosure
+\e8________________________________________________________________
+      compiled         binary with discipline         8.2
+  lambda or lexpr           _\be_\bq to lambda
+      function
+\e8________________________________________________________________
+      compiled         binary with discipline         8.2
+  nlambda function         _\be_\bq to nlambda
+\e8________________________________________________________________
+      compiled         binary with discipline         8.3
+       macro                _\be_\bq to macro
+\e8________________________________________________________________
+      foreign          binary with discipline         8.5
+     subroutine          of "subroutine"[]
+\e8________________________________________________________________
+      foreign          binary with discipline         8.5
+      function            of "function"[]
+\e8________________________________________________________________
+      foreign          binary with discipline         8.5
+  integer function    of "integer-function"[]
+\e8________________________________________________________________
+      foreign          binary with discipline         8.5
+   real function        of "real-function"[]
+\e8________________________________________________________________
+      foreign          binary with discipline         8.5
+     C function          of "c-function"[]
+\e8________________________________________________________________
+      foreign          binary with discipline         8.5
+  double function     of "double-c-function"[]
+\e8________________________________________________________________
+      foreign          binary with discipline         8.5
+ structure function   of "vector-c-function"[]
+\e8________________________________________________________________
+       array                array object               9
+\e8________________________________________________________________
+\e7\b|\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9                   |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9                                              |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9                                                               |\b\e8|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9                         Table 8.1
+
+____________________
+\e9   []Only the first character of the string is significant (i.e "s"
+is ok for "subroutine")
+
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                         8-3
+
+
+           Lambda and lexpr functions both  compile  into  a
+      binary object with a discipline of lambda.  However, a
+      compiled lexpr still acts like an interpreted lexpr.
+
+
+
+   8.3.  macros
+
+           An important feature of Lisp is  its  ability  to
+      manipulate  programs  as  data.   As a result of this,
+      most Lisp implementations  have  very  powerful  macro
+      facilities.  The Lisp language's macro facility can be
+      used to incorporate  popular  features  of  the  other
+      languages  into  Lisp.   For  example, there are macro
+      packages which allow one to create records  (ala  Pas-
+      cal)  and  refer  to  elements of those records by the
+      field names.  The _\bs_\bt_\br_\bu_\bc_\bt package imported from Maclisp
+      does  this.   Another  popular  use  for  macros is to
+      create more readable control structures  which  expand
+      into  _\bc_\bo_\bn_\bd,  _\bo_\br  and  _\ba_\bn_\bd.  One such example is the If
+      macro.  It allows you to write
+
+      (_\bI_\bf (_\be_\bq_\bu_\ba_\bl _\bn_\bu_\bm_\bb _\b0) _\bt_\bh_\be_\bn (_\bp_\br_\bi_\bn_\bt '_\bz_\be_\br_\bo) (_\bt_\be_\br_\bp_\br)
+       _\be_\bl_\bs_\be_\bi_\bf (_\be_\bq_\bu_\ba_\bl _\bn_\bu_\bm_\bb _\b1) _\bt_\bh_\be_\bn (_\bp_\br_\bi_\bn_\bt '_\bo_\bn_\be) (_\bt_\be_\br_\bp_\br)
+       _\be_\bl_\bs_\be (_\bp_\br_\bi_\bn_\bt '|_\bI _\bg_\bi_\bv_\be _\bu_\bp|))
+
+      which expands to
+
+      (_\bc_\bo_\bn_\bd
+          ((_\be_\bq_\bu_\ba_\bl _\bn_\bu_\bm_\bb _\b0) (_\bp_\br_\bi_\bn_\bt '_\bz_\be_\br_\bo) (_\bt_\be_\br_\bp_\br))
+          ((_\be_\bq_\bu_\ba_\bl _\bn_\bu_\bm_\bb _\b1) (_\bp_\br_\bi_\bn_\bt '_\bo_\bn_\be) (_\bt_\be_\br_\bp_\br))
+          (_\bt (_\bp_\br_\bi_\bn_\bt '|_\bI _\bg_\bi_\bv_\be _\bu_\bp|)))
+
+
+
+
+      8.3.1.  macro forms
+
+              A macro is a function  which  accepts  a  Lisp
+         expression   as  input  and  returns  another  Lisp
+         expression.  The action the macro takes  is  called
+         macro expansion.  Here is a simple example:
+
+         -> (_\bd_\be_\bf _\bf_\bi_\br_\bs_\bt (_\bm_\ba_\bc_\br_\bo (_\bx) (_\bc_\bo_\bn_\bs '_\bc_\ba_\br (_\bc_\bd_\br _\bx))))
+         first
+         -> (_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc))
+         a
+         -> (_\ba_\bp_\bp_\bl_\by '_\bf_\bi_\br_\bs_\bt '(_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc)))
+         (car '(a b c))
+
+         The first input line defines a macro called  _\bf_\bi_\br_\bs_\bt.
+         Notice  that the macro has one formal parameter, _\bx.
+         On the second input line, we ask the interpreter to
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                         8-4
+
+
+         evaluate  (_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc)).   _\bE_\bv_\ba_\bl  sees that _\bf_\bi_\br_\bs_\bt
+         has a function definition  of  type  macro,  so  it
+         evaluates  _\bf_\bi_\br_\bs_\bt's definition, passing to _\bf_\bi_\br_\bs_\bt, as
+         an argument, the form _\be_\bv_\ba_\bl  itself  was  trying  to
+         evaluate:  (_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc)).  The _\bf_\bi_\br_\bs_\bt macro chops
+         off the car of the argument with _\bc_\bd_\br, cons'  a  _\bc_\ba_\br
+         at   the   beginning   of   the  list  and  returns
+         (_\bc_\ba_\br '(_\ba _\bb _\bc)), which _\be_\bv_\ba_\bl evaluates.  The value  _\ba
+         is returned as the value of (_\bf_\bi_\br_\bs_\bt '(_\ba _\bb _\bc)).  Thus
+         whenever _\be_\bv_\ba_\bl tries to evaluate a  list  whose  car
+         has  a macro definition it ends up doing (at least)
+         two operations, the first of which is a call to the
+         macro  to  let  it  macro  expand the form, and the
+         other is the evaluation of the result of the macro.
+         The  result of the macro may be yet another call to
+         a macro, so _\be_\bv_\ba_\bl may have to do even  more  evalua-
+         tions  until it can finally determine the  value of
+         an expression.  One way to see  how  a  macro  will
+         expand  is to use _\ba_\bp_\bp_\bl_\by as shown on the third input
+         line above.
+
+
+
+      8.3.2.  defmacro
+
+              The macro _\bd_\be_\bf_\bm_\ba_\bc_\br_\bo makes it easier  to  define
+         macros  because it allows you to name the arguments
+         to the macro call.  For example,  suppose  we  find
+         ourselves      often      writing     code     like
+         (_\bs_\be_\bt_\bq _\bs_\bt_\ba_\bc_\bk (_\bc_\bo_\bn_\bs _\bn_\be_\bw_\be_\bl_\bt _\bs_\bt_\ba_\bc_\bk).  We could define a
+         macro  named  _\bp_\bu_\bs_\bh  to  do this for us.  One way to
+         define it is:
+
+         -> (_\bd_\be_\bf _\bp_\bu_\bs_\bh
+               (_\bm_\ba_\bc_\br_\bo (_\bx) (_\bl_\bi_\bs_\bt '_\bs_\be_\bt_\bq (_\bc_\ba_\bd_\bd_\br _\bx) (_\bl_\bi_\bs_\bt '_\bc_\bo_\bn_\bs (_\bc_\ba_\bd_\br _\bx) (_\bc_\ba_\bd_\bd_\br _\bx)))))
+         push
+
+         then (_\bp_\bu_\bs_\bh _\bn_\be_\bw_\be_\bl_\bt _\bs_\bt_\ba_\bc_\bk) will expand  to  the  form
+         mentioned above.  The same macro written using def-
+         macro would be:
+
+         -> (_\bd_\be_\bf_\bm_\ba_\bc_\br_\bo _\bp_\bu_\bs_\bh (_\bv_\ba_\bl_\bu_\be _\bs_\bt_\ba_\bc_\bk)
+           (_\bl_\bi_\bs_\bt '_\bs_\be_\bt_\bq ,_\bs_\bt_\ba_\bc_\bk (_\bl_\bi_\bs_\bt '_\bc_\bo_\bn_\bs ,_\bv_\ba_\bl_\bu_\be ,_\bs_\bt_\ba_\bc_\bk)))
+         push
+
+         Defmacro allows you to name the  arguments  of  the
+         macro  call,  and  makes  the macro definition look
+         more like a function definition.
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                         8-5
+
+
+      8.3.3.  the backquote character macro
+
+              The default syntax for  FRANZ  LISP  has  four
+         characters  with  associated character macros.  One
+         is semicolon for  comments.   Two  others  are  the
+         backquote and comma which are used by the backquote
+         character macro.  The  fourth  is  the  sharp  sign
+         macro described in the next section.
+
+              The backquote macro is used  to  create  lists
+         where many of the elements are fixed (quoted). This
+         makes it very useful  for  creating  macro  defini-
+         tions.  In the simplest case, a backquote acts just
+         like a single quote:
+
+         ->`(_\ba _\bb _\bc _\bd _\be)
+         (a b c d e)
+
+         If a comma precedes an element of a backquoted list
+         then that element is evaluated and its value is put
+         in the list.
+
+         ->(_\bs_\be_\bt_\bq _\bd '(_\bx _\by _\bz))
+         (x y z)
+         ->`(_\ba _\bb _\bc ,_\bd _\be)
+         (a b c (x y z) e)
+
+         If a comma followed by an at sign precedes an  ele-
+         ment  in  a  backquoted  list, then that element is
+         evaluated and spliced into the list with _\ba_\bp_\bp_\be_\bn_\bd.
+
+         ->`(_\ba _\bb _\bc ,@_\bd _\be)
+         (a b c x y z e)
+
+         Once a list begins with a backquote, the commas may
+         appear anywhere in the list as this example shows:
+
+         ->`(_\ba _\bb (_\bc _\bd ,(_\bc_\bd_\br _\bd)) (_\be _\bf (_\bg _\bh ,@(_\bc_\bd_\bd_\br _\bd) ,@_\bd)))
+         (a b (c d (y z)) (e f (g h z x y z)))
+
+         It is also possible and sometimes  even  useful  to
+         use  the backquote macro within itself.  As a final
+         demonstration of  the  backquote  macro,  we  shall
+         define  the  first  and  push  macros using all the
+         power at our disposal: defmacro and  the  backquote
+         macro.
+
+         ->(_\bd_\be_\bf_\bm_\ba_\bc_\br_\bo _\bf_\bi_\br_\bs_\bt (_\bl_\bi_\bs_\bt) `(_\bc_\ba_\br ,_\bl_\bi_\bs_\bt))
+         first
+         ->(_\bd_\be_\bf_\bm_\ba_\bc_\br_\bo _\bp_\bu_\bs_\bh (_\bv_\ba_\bl_\bu_\be _\bs_\bt_\ba_\bc_\bk) `(_\bs_\be_\bt_\bq ,_\bs_\bt_\ba_\bc_\bk (_\bc_\bo_\bn_\bs ,_\bv_\ba_\bl_\bu_\be ,_\bs_\bt_\ba_\bc_\bk)))
+         stack
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                         8-6
+
+
+      8.3.4.  sharp sign character macro
+
+              The sharp sign macro can perform a  number  of
+         different  functions   at read time.  The character
+         directly following the sharp sign determines  which
+         function  will  be  done,  and  following  Lisp  s-
+         expressions may serve as arguments.
+
+
+
+         8.3.4.1.  conditional inclusion
+
+            If you plan to run one source file in more  than
+            one environment then you may want to some pieces
+            of code to be included  or not included  depend-
+            ing  on  the  environment.  The  C language uses
+            "#ifdef" and "#ifndef"  for  this  purpose,  and
+            Lisp  uses  "#+" and "#-".  The environment that
+            the   sharp   sign   macro   checks    is    the
+            (_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be_\bs) list which is initialized when
+            the Lisp system  is  built   and  which  may  be
+            altered     by     (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be _\bf_\bo_\bo)     and
+            (_\bs_\bs_\bt_\ba_\bt_\bu_\bs _\bn_\bo_\bf_\be_\ba_\bt_\bu_\br_\be _\bb_\ba_\br) The form  of conditional
+            inclusion is
+                        _\b#_\b+_\bw_\bh_\be_\bn _\bw_\bh_\ba_\bt
+            where _\bw_\bh_\be_\bn is either a symbol or  an  expression
+            involving symbols and the functions _\ba_\bn_\bd, _\bo_\br, and
+            _\bn_\bo_\bt.  The meaning is that _\bw_\bh_\ba_\bt will only be read
+            in  if  _\bw_\bh_\be_\bn  is true.  A symbol in _\bw_\bh_\be_\bn is true
+            only if  it  appears  in  the  (_\bs_\bt_\ba_\bt_\bu_\bs _\bf_\be_\ba_\bt_\bu_\br_\be_\bs)
+            list.
+
+
+    ____________________________________________________
+
+    ; suppose we want to write a program which references a file
+    ; and which can run at ucb, ucsd and cmu where the file naming conventions
+    ; are different.
+    ;
+    -> (_\bd_\be_\bf_\bu_\bn _\bh_\bo_\bw_\bo_\bl_\bd (_\bn_\ba_\bm_\be)
+          (_\bt_\be_\br_\bp_\br)
+          (_\bl_\bo_\ba_\bd #+(_\bo_\br _\bu_\bc_\bb _\bu_\bc_\bs_\bd) "/_\bu_\bs_\br/_\bl_\bi_\bb/_\bl_\bi_\bs_\bp/_\ba_\bg_\be_\bs._\bl"
+                 #+_\bc_\bm_\bu "/_\bu_\bs_\br/_\bl_\bi_\bs_\bp/_\bd_\bo_\bc/_\ba_\bg_\be_\bs._\bl")
+          (_\bp_\ba_\bt_\bo_\bm _\bn_\ba_\bm_\be)
+          (_\bp_\ba_\bt_\bo_\bm " _\bi_\bs ")
+          (_\bp_\br_\bi_\bn_\bt (_\bc_\bd_\br (_\ba_\bs_\bs_\bo_\bc _\bn_\ba_\bm_\be _\ba_\bg_\be_\bf_\bi_\bl_\be)))
+          (_\bp_\ba_\bt_\bo_\bm "_\by_\be_\ba_\br_\bs _\bo_\bl_\bd")
+          (_\bt_\be_\br_\bp_\br))
+    ____________________________________________________
+
+
+
+The form
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                         8-7
+
+
+                        _\b#_\b-_\bw_\bh_\be_\bn _\bw_\bh_\ba_\bt
+is equivalent to
+                     _\b#_\b+_\b(_\bn_\bo_\bt _\bw_\bh_\be_\bn_\b) _\bw_\bh_\ba_\bt
+
+
+
+         8.3.4.2.  fixnum character equivalents
+
+            When working with fixnum equivalents of  charac-
+            ters,  it  is  often hard to remember the number
+            corresponding to a character.  The form
+                            _\b#_\b/_\bc
+            is equivalent to the  fixnum  representation  of
+            character c.
+
+
+    ____________________________________________________
+
+    ; a function which returns t if the user types y else it returns nil.
+    ;
+    -> (_\bd_\be_\bf_\bu_\bn _\by_\be_\bs_\bo_\br_\bn_\bo _\bn_\bi_\bl
+          (_\bp_\br_\bo_\bg_\bn (_\ba_\bn_\bs)
+                 (_\bs_\be_\bt_\bq _\ba_\bn_\bs (_\bt_\by_\bi))
+                 (_\bc_\bo_\bn_\bd ((_\be_\bq_\bu_\ba_\bl _\ba_\bn_\bs #/_\by) _\bt)
+                       (_\bt _\bn_\bi_\bl))))
+    ____________________________________________________
+
+
+
+
+
+
+         8.3.4.3.  read time evaluation
+
+            Occasionally you want to express a constant as a
+            Lisp  expression,  yet you don't want to pay the
+            penalty of evaluating this expression each  time
+            it is referenced.  The form
+                        _\b#_\b._\be_\bx_\bp_\br_\be_\bs_\bs_\bi_\bo_\bn
+            evaluates  the  expression  at  read  time   and
+            returns its value.
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                         8-8
+
+
+
+    ____________________________________________________
+
+    ; a function to test if any of bits 1 3 or 12 are set in a fixnum.
+    ;
+    -> (_\bd_\be_\bf_\bu_\bn _\bt_\be_\bs_\bt_\bi_\bt (_\bn_\bu_\bm)
+          (_\bc_\bo_\bn_\bd ((_\bz_\be_\br_\bo_\bp (_\bb_\bo_\bo_\bl_\be _\b1 _\bn_\bu_\bm #.(+ (_\bl_\bs_\bh _\b1 _\b1) (_\bl_\bs_\bh _\b1 _\b3) (_\bl_\bs_\bh _\b1 _\b1_\b2))))
+                 _\bn_\bi_\bl)
+                (_\bt _\bt)))
+    ____________________________________________________
+
+
+
+
+
+
+   8.4.  fclosures
+
+           Fclosures are a type of functional  object.   The
+      purpose  is  to  remember the values of some variables
+      between invocations of the functional  object  and  to
+      protect this data from being inadvertently overwritten
+      by other Lisp  functions.   Fortran  programs  usually
+      exhibit  this behavior for their variables.  (In fact,
+      some versions of Fortran would require  the  variables
+      to  be  in COMMON).  Thus it is easy to write a linear
+      congruent random number generator in  Fortran,  merely
+      by keeping the seed as a variable in the function.  It
+      is much more risky to do so in Lisp, since any special
+      variable you picked, might be used by some other func-
+      tion.  Fclosures are an attempt to provide most of the
+      same  functionality  as closures in Lisp Machine Lisp,
+      to users of FRANZ LISP.  Fclosures are related to clo-
+      sures in this way:
+      (fclosure '(a b) 'foo) <==>
+              (let ((a a) (b b)) (closure '(a b) 'foo))
+
+
+
+      8.4.1.  an example
+
+____________________________________________________________
+
+% lisp
+Franz Lisp, Opus 38.60
+->(defun code (me count)
+  (print (list 'in x))
+  (setq x (+ 1 x))
+  (cond ((greaterp count 1) (funcall me me (sub1 count))))
+  (print (list 'out x)))
+code
+->(defun tester (object count)
+  (funcall object object count) (terpri))
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                         8-9
+
+
+tester
+->(setq x 0)
+0
+->(setq z (fclosure '(x) 'code))
+fclosure[8]
+-> (tester z 3)
+(in 0)(in 1)(in 2)(out 3)(out 3)(out 3)
+nil
+->x
+0
+____________________________________________________________
+
+
+
+
+
+              The function _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be  creates  a  new  object
+         that  we  will  call  an  fclosure, (although it is
+         actually a vector).  The fclosure contains a  func-
+         tional  object, and a set of symbols and values for
+         the symbols.  In the above  example,  the  fclosure
+         functional object is the function code.  The set of
+         symbols and values just contains the symbol `x' and
+         zero,  the  value  of  `x'  when  the  fclosure was
+         created.
+
+         When an fclosure is funcall'ed:
+
+         1)   The Lisp system lambda binds  the  symbols  in
+              the fclosure to their values in the fclosure.
+
+         2)   It continues the  funcall  on  the  functional
+              object of the fclosure.
+
+         3)   Finally, it un-lambda binds the symbols in the
+              fclosure  and  at  the  same  time  stores the
+              current values of the symbols in the fclosure.
+
+
+              Notice that the fclosure is saving  the  value
+         of  the  symbol  `x'.   Each  time  a  fclosure  is
+         created, new space  is  allocated  for  saving  the
+         values  of the symbols. Thus if we execute fclosure
+         again, over the same  function,  we  can  have  two
+         independent counters:
+
+____________________________________________________________
+
+-> (setq zz (fclosure '(x) 'code))
+fclosure[1]
+-> (tester zz 2)
+(in 0)(in 1)(out 2)(out 2)
+-> (tester zz 2)
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                        8-10
+
+
+(in 2)(in 3)(out 4)(out 4)
+-> (tester z 3)
+(in 3)(in 4)(in 5)(out 6)(out 6)(out 6)
+____________________________________________________________
+
+
+
+
+
+
+
+      8.4.2.  useful functions
+
+              Here are some quick some  summaries  of  func-
+         tions  dealing  with  closures.  They are more for-
+         mally defined in 2.8.4.  To  recap,  fclosures  are
+         made by (_\bf_\bc_\bl_\bo_\bs_\bu_\br_\be '_\bl__\bv_\ba_\br_\bs '_\bg__\bf_\bu_\bn_\bc_\bo_\bb_\bj).  l_vars is a
+         list of symbols (not containing nil), g_funcobj  is
+         any  object  that can be funcalled.  (Objects which
+         can be funcalled, include compiled Lisp  functions,
+         lambda  expressions,  symbols,  foreign  functions,
+         etc.) In general, if you want a  compiled  function
+         to  be closed over a variable, you must declare the
+         variable  to  be  special  within   the   function.
+         Another example would be:
+
+                     (fclosure '(a b) #'(lambda (x) (plus x a)))
+
+         Here, the #' construction will  make  the  compiler
+         compile the lambda expression.
+
+              There are times when you want to  share  vari-
+         ables  between  fclosures.  This can be done if the
+         fclosures  are  created  at  the  same  time  using
+         _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be-_\bl_\bi_\bs_\bt.  The function _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be-_\ba_\bl_\bi_\bs_\bt returns
+         an assoc list giving the symbols and values in  the
+         fclosure.   The  predicate  _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be_\bp returns t iff
+         its  argument  is  a  fclosure.   Other   functions
+         imported  from  Lisp  Machine  Lisp are _\bs_\by_\bm_\be_\bv_\ba_\bl-_\bi_\bn-
+         _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be,   _\bl_\be_\bt-_\bf_\bc_\bl_\bo_\bs_\be_\bd,    and    _\bs_\be_\bt-_\bi_\bn-_\bf_\bc_\bl_\bo_\bs_\bu_\br_\be.
+         Lastly,  the function _\bf_\bc_\bl_\bo_\bs_\bu_\br_\be-_\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn returns the
+         function argument.
+
+
+
+      8.4.3.  internal structure
+
+              Currently, closures are  implemented  as  vec-
+         tors, with property being the symbol fclosure.  The
+         functional object is the first entry.  The  remain-
+         ing  entries are structures which point to the sym-
+         bols and values for the closure, (with a  reference
+         count  to  determine  if  a  recursive  closure  is
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                        8-11
+
+
+         active).
+
+
+
+   8.5.  foreign subroutines and functions
+
+           FRANZ LISP has the ability  to  dynamically  load
+      object  files  produced by other compilers and to call
+      functions defined in those files.  These functions are
+      called _\bf_\bo_\br_\be_\bi_\bg_\bn functions.* There are  seven  types  of
+      foreign functions.  They are characterized by the type
+      of result they  return,  and  by  differences  in  the
+      interpretation of their arguments.  They come from two
+      families: a group  suited  for  languages  which  pass
+      arguments  by  reference  (e.g.  Fortran), and a group
+      suited for languages which  pass  arguments  by  value
+      (e.g. C).
+
+
+      There are four types in the first group:
+
+      subroutine
+           This does not return anything.  The  Lisp  system
+           always returns t after calling a subroutine.
+
+      function
+           This returns whatever the function returns.  This
+           must  be  a valid Lisp object or it may cause the
+           Lisp system to fail.
+
+      integer-function
+           This returns an integer  which  the  Lisp  system
+           makes into a fixnum and returns.
+
+      real-function
+           This returns a double precision real number which
+           the Lisp system makes into a flonum and returns.
+
+
+      There are three types in the second group:
+
+      c-function
+           This is like an integer function, except for  its
+           different interpretation of arguments.
+
+
+____________________
+\e9   *This topic is also discussed in Report  PAM-124  of  the
+Center  for  Pure  and  Applied  Mathematics,  UCB, entitled
+``Parlez-Vous Franz?  An Informal Introduction to  Interfac-
+ing Foreign Functions to Franz LISP'', by James R. Larus
+
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                        8-12
+
+
+      double-c-function
+           This is like a real-function.
+
+      vector-c-function
+           This is for C functions which return a structure.
+           The  first  argument  to such functions must be a
+           vector (of type vectori), into which  the  result
+           is  stored.  The second Lisp argument becomes the
+           first argument to the C function, and so on
+
+      A foreign function is accessed through a binary object
+      just like a compiled Lisp function.  The difference is
+      that the discipline field of a  binary  object  for  a
+      foreign  function is a string whose first character is
+      given in the following table:
+
+
+\e8                   ____________________________
+                    letter         type
+\e8                   ____________________________\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b____________________________
+                      s         subroutine
+\e8                   ____________________________
+                      f          function
+\e8                   ____________________________
+                      i      integer-function
+\e8                   ____________________________
+                      r       real-function.
+\e8                   ____________________________
+                      c         c-function
+\e8                   ____________________________
+                      v      vector-c-function
+\e8                   ____________________________
+                      d      double-c-function
+\e8                   ____________________________
+\e7                  |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+                          |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+                                              |\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|\b\e7|
+
+
+
+
+
+
+
+
+
+
+
+
+      Two functions  are  provided  for  setting-up  foreign
+      functions.   _\bC_\bf_\ba_\bs_\bl  loads an object file into the Lisp
+      system and sets up one foreign function binary object.
+      If there are more than one function in an object file,
+      _\bg_\be_\bt_\ba_\bd_\bd_\br_\be_\bs_\bs can be used to set  up  additional  foreign
+      function objects.
+
+           Foreign  functions are  called  just  like  other
+      functions,  e.g  (_\bf_\bu_\bn_\bn_\ba_\bm_\be _\ba_\br_\bg_\b1 _\ba_\br_\bg_\b2).  When a function
+      in the Fortran group  is  called,  the  arguments  are
+      evaluated  and  then  examined.  List, hunk and symbol
+      arguments are passed unchanged to  the  foreign  func-
+      tion.   Fixnum  and flonum arguments are copied into a
+      temporary location and  a  pointer  to  the  value  is
+      passed (this is because Fortran uses call by reference
+      and it is dangerous to modify the contents of a fixnum
+      or  flonum  which  something else might point to).  If
+      the argument is an array object, the data field of the
+      array  object  is passed to the foreign function (This
+      is the easiest way to send large amounts  of  data  to
+      and receive large amounts of data from a foreign func-
+      tion).  If a binary object is an argument,  the  entry
+
+
+\e9                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                        8-13
+
+
+      field of that object is passed to the foreign function
+      (the entry field is the address of a function, so this
+      amounts to passing a function as an argument).
+
+           When a function in the C group is called,  fixnum
+      and flownum arguments are passed by value.  For almost
+      all other arguments, the address is merely provided to
+      the  C  routine.   The  only exception arises when you
+      want to invoke a C routine which  expects  a  ``struc-
+      ture''  argument.  Recall that a (rarely used) feature
+      of the C language is the ability to pass structures by
+      value.   This  copies  the  structure  onto the stack.
+      Since the Franz's nearest equivalent to a C  structure
+      is  a  vector, we provide an escape clause to copy the
+      contents of an immediate-type vector by value.  If the
+      property  field  of  a vectori argument, is the symbol
+      "value-structure-argument", then the  binary  data  of
+      this immediate-type vector is copied into the argument
+      list of the C routine.
+
+           The method a foreign function uses to access  the
+      arguments   provided  by  Lisp  is  dependent  on  the
+      language  of  the  foreign  function.   The  following
+      scripts  demonstrate  how  how  Lisp can interact with
+      three languages: C, Pascal and Fortran.  C and  Pascal
+      have  pointer  types and the first script shows how to
+      use pointers to extract information from Lisp objects.
+      There  are  two  functions  defined for each language.
+      The first (cfoo in C, pfoo in Pascal)  is  given  four
+      arguments,  a  fixnum, a flonum-block array, a hunk of
+      at least two fixnums and a list of at least  two  fix-
+      nums.   To  demonstrate  that  the values were passed,
+      each ?foo function prints its arguments (or  parts  of
+      them).   The  ?foo  function  then modifies the second
+      element of the flonum-block array and returns a  3  to
+      Lisp.   The second function (cmemq in C, pmemq in Pas-
+      cal) acts just like the Lisp _\bm_\be_\bm_\bq function (except  it
+      won't work for fixnums whereas the lisp _\bm_\be_\bm_\bq will work
+      for small fixnums).  In the script, typed input is  in
+      bold,  computer output is in roman and comments are in
+      _\bi_\bt_\ba_\bl_\bi_\bc.
+
+
+____________________________________________________________
+
+_\bT_\bh_\be_\bs_\be _\ba_\br_\be _\bt_\bh_\be _\bC _\bc_\bo_\bd_\be_\bd _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs
+% cat ch8auxc.c
+/* demonstration of c coded foreign integer-function */
+
+/* the following will be used to extract fixnums out of a list of fixnums */
+struct listoffixnumscell
+{    struct listoffixnumscell *cdr;
+     int *fixnum;
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                        8-14
+
+
+};
+
+struct listcell
+{       struct listcell *cdr;
+        int car;
+};
+
+cfoo(a,b,c,d)
+int *a;
+double b[];
+int *c[];
+struct listoffixnumscell *d;
+{
+    printf("a: %d, b[0]: %f, b[1]: %f0, *a, b[0], b[1]);
+    printf(" c (first): %d   c (second): %d0,
+               *c[0],*c[1]);
+    printf(" ( %d %d ... ) ", *(d->fixnum), *(d->cdr->fixnum));
+    b[1] = 3.1415926;
+    return(3);
+}
+
+struct listcell *
+cmemq(element,list)
+int element;
+struct listcell *list;
+{
+   for( ; list && element != list->car ;  list = list->cdr);
+   return(list);
+}
+
+
+_\bT_\bh_\be_\bs_\be _\ba_\br_\be _\bt_\bh_\be _\bP_\ba_\bs_\bc_\ba_\bl _\bc_\bo_\bd_\be_\bd _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs
+% cat ch8auxp.p
+type    pinteger = ^integer;
+        realarray = array[0..10] of real;
+        pintarray = array[0..10] of pinteger;
+        listoffixnumscell = record
+                                cdr  : ^listoffixnumscell;
+                                fixnum : pinteger;
+                            end;
+        plistcell = ^listcell;
+        listcell = record
+                      cdr : plistcell;
+                      car : integer;
+                   end;
+
+function pfoo ( var a : integer ;
+                var b : realarray;
+                var c : pintarray;
+                var d : listoffixnumscell) : integer;
+begin
+   writeln(' a:',a, ' b[0]:', b[0], ' b[1]:', b[1]);
+   writeln(' c (first):', c[0]^,' c (second):', c[1]^);
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                        8-15
+
+
+   writeln(' ( ', d.fixnum^, d.cdr^.fixnum^, ' ...) ');
+   b[1] := 3.1415926;
+   pfoo := 3
+end ;
+
+{ the function pmemq looks for the Lisp pointer given as the first argument
+  in the list pointed to by the second argument.
+  Note that we declare " a : integer " instead of " var a : integer " since
+  we are interested in the pointer value instead of what it points to (which
+  could be any Lisp object)
+}
+function pmemq( a : integer; list : plistcell) : plistcell;
+begin
+ while (list <> nil) and (list^.car <> a) do list := list^.cdr;
+ pmemq := list;
+end ;
+
+
+_\bT_\bh_\be _\bf_\bi_\bl_\be_\bs _\ba_\br_\be _\bc_\bo_\bm_\bp_\bi_\bl_\be_\bd
+% cc -c ch8auxc.c
+1.0u 1.2s 0:15 14% 30+39k 33+20io 147pf+0w
+% pc -c ch8auxp.p
+3.0u 1.7s 0:37 12% 27+32k 53+32io 143pf+0w
+
+
+% lisp
+Franz Lisp, Opus 38.60
+_\bF_\bi_\br_\bs_\bt _\bt_\bh_\be _\bf_\bi_\bl_\be_\bs _\ba_\br_\be _\bl_\bo_\ba_\bd_\be_\bd _\ba_\bn_\bd _\bw_\be _\bs_\be_\bt _\bu_\bp _\bo_\bn_\be  _\bf_\bo_\br_\be_\bi_\bg_\bn  _\bf_\bu_\bn_\bc_\b-
+_\bt_\bi_\bo_\bn  _\bb_\bi_\bn_\ba_\br_\by.  _\bW_\be _\bh_\ba_\bv_\be _\bt_\bw_\bo _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn_\bs _\bi_\bn _\be_\ba_\bc_\bh _\bf_\bi_\bl_\be _\bs_\bo _\bw_\be _\bm_\bu_\bs_\bt
+_\bc_\bh_\bo_\bo_\bs_\be _\bo_\bn_\be _\bt_\bo _\bt_\be_\bl_\bl _\bc_\bf_\ba_\bs_\bl _\ba_\bb_\bo_\bu_\bt.  _\bT_\bh_\be _\bc_\bh_\bo_\bi_\bc_\be _\bi_\bs _\ba_\br_\bb_\bi_\bt_\br_\ba_\br_\by.
+-> (cfasl 'ch8auxc.o '_cfoo 'cfoo "integer-function")
+/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxc.o -e _cfoo -o /tmp/Li7055.0  -lc
+#63000-"integer-function"
+-> (cfasl 'ch8auxp.o '_pfoo 'pfoo "integer-function" "-lpc")
+/usr/lib/lisp/nld -N -A /tmp/Li7055.0 -T 63200 ch8auxp.o -e _pfoo -o /tmp/Li7055.1 -lpc -lc
+#63200-"integer-function"
+_\bH_\be_\br_\be _\bw_\be _\bs_\be_\bt _\bu_\bp _\bt_\bh_\be _\bo_\bt_\bh_\be_\br _\bf_\bo_\br_\be_\bi_\bg_\bn _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn _\bb_\bi_\bn_\ba_\br_\by _\bo_\bb_\bj_\be_\bc_\bt_\bs
+-> (getaddress '_cmemq 'cmemq "function" '_pmemq 'pmemq "function")
+#6306c-"function"
+_\bW_\be _\bw_\ba_\bn_\bt _\bt_\bo _\bc_\br_\be_\ba_\bt_\be _\ba_\bn_\bd _\bi_\bn_\bi_\bt_\bi_\ba_\bl_\bi_\bz_\be _\ba_\bn _\ba_\br_\br_\ba_\by  _\bt_\bo  _\bp_\ba_\bs_\bs  _\bt_\bo  _\bt_\bh_\be
+_\bc_\bf_\bo_\bo  _\bf_\bu_\bn_\bc_\bt_\bi_\bo_\bn.  _\bI_\bn _\bt_\bh_\bi_\bs _\bc_\ba_\bs_\be _\bw_\be _\bc_\br_\be_\ba_\bt_\be _\ba_\bn _\bu_\bn_\bn_\ba_\bm_\be_\bd _\ba_\br_\br_\ba_\by _\ba_\bn_\bd
+_\bs_\bt_\bo_\br_\be _\bi_\bt _\bi_\bn _\bt_\bh_\be _\bv_\ba_\bl_\bu_\be _\bc_\be_\bl_\bl _\bo_\bf _\bt_\be_\bs_\bt_\ba_\br_\br.  _\bW_\bh_\be_\bn  _\bw_\be  _\bc_\br_\be_\ba_\bt_\be  _\ba_\bn
+_\ba_\br_\br_\ba_\by  _\bt_\bo  _\bp_\ba_\bs_\bs  _\bt_\bo  _\bt_\bh_\be  _\bP_\ba_\bs_\bc_\ba_\bl _\bp_\br_\bo_\bg_\br_\ba_\bm _\bw_\be _\bw_\bi_\bl_\bl _\bu_\bs_\be _\ba _\bn_\ba_\bm_\be_\bd
+_\ba_\br_\br_\ba_\by _\bj_\bu_\bs_\bt _\bt_\bo _\bd_\be_\bm_\bo_\bn_\bs_\bt_\br_\ba_\bt_\be _\bt_\bh_\be _\bd_\bi_\bf_\bf_\be_\br_\be_\bn_\bt _\bw_\ba_\by _\bt_\bh_\ba_\bt  _\bn_\ba_\bm_\be_\bd  _\ba_\bn_\bd
+_\bu_\bn_\bn_\ba_\bm_\be_\bd _\ba_\br_\br_\ba_\by_\bs _\ba_\br_\be _\bc_\br_\be_\ba_\bt_\be_\bd _\ba_\bn_\bd _\ba_\bc_\bc_\be_\bs_\bs_\be_\bd.
+-> (setq testarr (array nil flonum-block 2))
+array[2]
+-> (store (funcall testarr 0) 1.234)
+1.234
+-> (store (funcall testarr 1) 5.678)
+5.678
+-> (cfoo 385 testarr (hunk 10 11 13 14) '(15 16 17))
+a: 385, b[0]: 1.234000, b[1]: 5.678000
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                        8-16
+
+
+ c (first): 10   c (second): 11
+ ( 15 16 ... )
+ 3
+_\bN_\bo_\bt_\be _\bt_\bh_\ba_\bt _\bc_\bf_\bo_\bo _\bh_\ba_\bs _\br_\be_\bt_\bu_\br_\bn_\be_\bd _\b3 _\ba_\bs _\bi_\bt _\bs_\bh_\bo_\bu_\bl_\bd.  _\bI_\bt _\ba_\bl_\bs_\bo _\bh_\ba_\bd _\bt_\bh_\be
+_\bs_\bi_\bd_\be  _\be_\bf_\bf_\be_\bc_\bt  _\bo_\bf  _\bc_\bh_\ba_\bn_\bg_\bi_\bn_\bg  _\bt_\bh_\be _\bs_\be_\bc_\bo_\bn_\bd _\bv_\ba_\bl_\bu_\be _\bo_\bf _\bt_\bh_\be _\ba_\br_\br_\ba_\by _\bt_\bo
+_\b3._\b1_\b4_\b1_\b5_\b9_\b2_\b6  _\bw_\bh_\bi_\bc_\bh _\bc_\bh_\be_\bc_\bk _\bn_\be_\bx_\bt.
+-> (funcall testarr 1)
+3.1415926
+
+
+_\bI_\bn _\bp_\br_\be_\bp_\ba_\br_\ba_\bt_\bi_\bo_\bn _\bf_\bo_\br _\bc_\ba_\bl_\bl_\bi_\bn_\bg _\bp_\bf_\bo_\bo _\bw_\be _\bc_\br_\be_\ba_\bt_\be _\ba_\bn _\ba_\br_\br_\ba_\by.
+-> (array test flonum-block 2)
+array[2]
+-> (store (test 0) 1.234)
+1.234
+-> (store (test 1) 5.678)
+5.678
+-> (pfoo 385 (getd 'test) (hunk 10 11 13 14) '(15 16 17))
+ a:       385 b[0]:  1.23400000000000E+00 b[1]:  5.67800000000000E+00
+ c (first):        10 c (second):        11
+ (         15        16 ...)
+3
+-> (test 1)
+3.1415926
+
+ _\bN_\bo_\bw _\bt_\bo _\bt_\be_\bs_\bt _\bo_\bu_\bt _\bt_\bh_\be _\bm_\be_\bm_\bq'_\bs
+-> (cmemq 'a '(b c a d e f))
+(_\ba _\bd _\be _\bf)
+-> (pmemq 'e '(a d f g a x))
+_\bn_\bi_\bl
+____________________________________________________________
+
+
+
+
+
+           The Fortran example will be much shorter since in
+      Fortran  you can't follow pointers as you can in other
+      languages.  The Fortran function ffoo is  given  three
+      arguments:  a  fixnum, a fixnum-block array and a flo-
+      num.  These arguments are printed out to  verify  that
+      they  made it and then the first value of the array is
+      modified.  The function  returns  a  double  precision
+      value  which  is  converted  to  a  flonum by lisp and
+      printed.  Note that the entry point  corresponding  to
+      the  Fortran function ffoo is _ffoo_ as opposed to the
+      C and Pascal convention of preceding the name with  an
+      underscore.
+
+____________________________________________________________
+
+
+% cat ch8auxf.f
+
+
+                                     Printed: August 5, 1983
+
+
+
+
+
+
+
+Functions, Fclosures, and Macros                        8-17
+
+
+        double precision function ffoo(a,b,c)
+        integer a,b(10)
+        double precision c
+        print 2,a,b(1),b(2),c
+2       format(' a=',i4,', b(1)=',i5,', b(2)=',i5,' c=',f6.4)
+        b(1) = 22
+        ffoo = 1.23456
+        return
+        end
+% f77 -c ch8auxf.f
+ch8auxf.f:
+   ffoo:
+0.9u 1.8s 0:12 22% 20+22k 54+48io 158pf+0w
+% lisp
+Franz Lisp, Opus 38.60
+-> (cfasl 'ch8auxf.o '_ffoo_ 'ffoo "real-function" "-lF77 -lI77")
+/usr/lib/lisp/nld -N -A /usr/local/lisp -T 63000 ch8auxf.o -e _ffoo_
+-o /tmp/Li11066.0 -lF77 -lI77 -lc
+#6307c-"real-function"
+
+-> (array test fixnum-block 2)
+array[2]
+-> (store (test 0) 10)
+10
+-> (store (test 1) 11)
+11
+-> (ffoo 385 (getd 'test) 5.678)
+ a= 385, b(1)=   10, b(2)=   11 c=5.6780
+1.234559893608093
+-> (test 0)
+22
+
+____________________________________________________________
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9                                     Printed: August 5, 1983
+
+
+
diff --git a/usr/src/ucb/lisp/lisplib/pp.l b/usr/src/ucb/lisp/lisplib/pp.l
new file mode 100644 (file)
index 0000000..56c61d2
--- /dev/null
@@ -0,0 +1,417 @@
+(setq rcs-pp-
+   "$Header: /usr/lib/lisp/RCS/pp.l,v 1.2 83/08/15 22:27:54 jkf Exp $")
+
+;;
+;; pp.l                                        -[Mon Aug 15 10:52:13 1983 by jkf]-
+;;
+;; pretty printer for franz lisp
+;;
+
+(declare (macros t))
+
+(declare (special poport pparm1 pparm2 lpar rpar form linel))
+; (declare (localf $patom1 $prd1 $prdf charcnt condclosefile))
+
+; =======================================
+; pretty printer top level routine pp
+;
+;
+; calling form- (pp arg1 arg2 ... argn)
+; the args may be names of functions, atoms with associated values
+; or output descriptors.
+; if argi is:
+;    an atom - it is assumed to be a function name, if there is no
+;             function property associated with it,then it is assumed
+;              to be an atom with a value
+;    (P port)-  port is the output port where the results of the
+;              pretty printing will be sent.
+;              poport is the default if no (P port) is given.
+;    (F fname)- fname is  a file name to write the results in
+;    (A atmname) - means, treat this as an atom with a value, dont
+;              check if it is the name of a function.
+;    (E exp)-   evaluate exp without printing anything
+;    other -   pretty-print the expression as is - no longer an error
+;
+;    Also, rather than printing only a function defn or only a value, we will
+;    let prettyprops decide which props to print.  Finally, prettyprops will
+;    follow the CMULisp format where each element is either a property
+;    or a dotted pair of the form (prop . fn) where in order to print the
+;    given property we call (fn id val prop).  The special properties
+;    function and value are used to denote those "properties" which
+;    do not actually appear on the plist.
+;
+; [history of this code: originally came from Harvard Lisp, hacked to
+; work under franz at ucb, hacked to work at cmu and finally rehacked
+; to work without special cmu macros]
+
+(declare (special $outport$ $fileopen$ prettyprops))
+
+(setq prettyprops '((comment . pp-comment)
+                   (function . pp-function)
+                   (value . pp-value)))
+
+; printret is like print yet it returns the value printed, this is used
+; by pp                
+(def printret
+  (macro ($l$)
+        `(progn (print ,@(cdr $l$)) ,(cadr $l$))))
+
+(def pp
+  (nlambda ($xlist$)
+       (prog ($gcprint $outport$ $cur$ $fileopen$ $prl$ $atm$)
+
+             (setq $gcprint nil)                       ; don't print
+                                                       ; gc messages in pp.
+
+             (setq $outport$ poport)                   ; default port
+             ; check if more to do, if not close output file if it is
+             ; open and leave
+
+
+   toploop    (cond ((null (setq $cur$ (car $xlist$)))
+                    (condclosefile)
+                    (terpr)
+                    (return t)))
+
+             (cond ((dtpr $cur$)
+                    (cond ((equal 'P (car $cur$))      ; specifying a port
+                           (condclosefile)             ; close file if open
+                           (setq $outport$ (eval (cadr $cur$))))
+
+                          ((equal 'F (car $cur$))      ; specifying a file
+                           (condclosefile)             ; close file if open
+                           (setq $outport$ (outfile (cadr $cur$))
+                                 $fileopen$ t))
+
+                                               
+                          ((equal 'E (car $cur$))
+                           (eval (cadr $cur$)))
+
+                          (t (pp-form $cur$ $outport$)))       ;-DNC inserted
+                    (go botloop)))
+
+
+      (mapc (function
+            (lambda (prop)
+                    (prog (printer)
+                          (cond ((dtpr prop)
+                                 (setq printer (cdr prop))
+                                 (setq prop (car prop)))
+                                (t (setq printer 'pp-prop)))
+                          (cond ((eq 'value prop)
+                                 (and (boundp $cur$)
+                                      (apply printer
+                                             (list $cur$
+                                                   (eval $cur$)
+                                                   'value))
+                                      (terpr $outport$)))
+                                ((eq 'function prop)
+                                 (and (getd $cur$)
+                                      (cond ((not (bcdp (getd $cur$)))
+                                             (apply printer
+                                                    (list $cur$
+                                                          (getd $cur$)
+                                                          'function)))
+                                            ; restore message about
+                                            ; bcd since otherwise you
+                                            ; just get nothing and
+                                            ; people were complaining.
+                                            ; - dhl.
+                                            #-cmu
+                                            (t
+                                             (msg N 
+                                                  "pp: function " 
+                                                  (or $cur$)
+                                                  " is machine coded (bcd) "))
+                                            )
+                                      (terpri $outport$)))
+                                ((get $cur$ prop)
+                                 (apply printer
+                                        (list $cur$
+                                              (get $cur$ prop)
+                                              prop))
+                                 (terpri $outport$))))))
+           prettyprops)
+
+
+ botloop      (setq $xlist$ (cdr $xlist$))
+
+             (go toploop))))
+
+(setq pparm1 50 pparm2 100)
+
+;   -DNC These "prettyprinter parameters" are used to decide when we should
+;      quit printing down the right margin and move back to the left -
+;      Do it when the leftmargin > pparm1 and there are more than pparm2
+;      more chars to print in the expression
+
+; cmu prefers dv instead of setq
+
+#+cmu
+(def pp-value (lambda (i v p)
+                     (terpri $outport$)
+                     (pp-form (list 'dv i v) $outport$)))
+
+#-cmu
+(def pp-value (lambda (i v p)
+                     ;;(terpr $outport$) ;; pp-form does an initial terpr.
+                     ;;                        we don't need two.
+                     (pp-form `(setq ,i ',v) $outport$)))
+
+(def pp-function (lambda (i v p)
+                        #+cmu (terpri $outport$)
+                        ;;
+                        ;; add test for traced functions and don't
+                        ;; print the trace mess, just the original
+                        ;; function.  - dhl.
+                        ;;
+                        ;; this test might belong in the main pp
+                        ;; loop but fits in easily here. - dhl
+                        ;;
+                        (cond ((and (dtpr v)
+                                    (dtpr (cadr v))
+                                    (memq (caadr v)
+                                          '(T-nargs T-arglist))
+                                    (cond ((bcdp (get i 'trace-orig-fcn))
+                                           #-cmu
+                                           (msg N 
+                                                "pp: function " 
+                                                (or i) 
+                                                " is machine coded (bcd) ")
+                                           t)
+                                          (t (pp-form 
+                                              (list 'def i 
+                                                    (get i 'trace-orig-fcn))
+                                              $outport$)
+                                             t))))
+                              ; this function need to return t, but
+                              ; pp-form returns nil sometimes.
+                              (t (pp-form (list 'def i v) $outport$)
+                                 t))))
+
+(def pp-prop (lambda (i v p)
+                    #+cmu (terpri $outport$)
+                    (pp-form (list 'defprop i v p) $outport$)))
+
+(def condclosefile 
+  (lambda nil
+         (cond ($fileopen$
+                (terpr $outport$)
+                (close $outport$)
+                (setq $fileopen$ nil)))))
+\f
+;
+; these routines are meant to be used by pp but since
+; some people insist on using them we will set $outport$ to nil
+; as the default
+(setq $outport$ nil)
+
+
+
+(defun pp-form (value &optional ($outport$ poport oport-p) (lmar 0))
+ ($prdf value lmar 0))
+
+; this is for compatability with old code, will remove soon -- jkf
+(def $prpr (lambda (x) (pp-form x $outport$)))
+
+
+\f
+(declare (special rmar))       ; -DNC this used to be m - I've tried to
+                               ; to fix up the pretty printer a bit.  It
+                               ; used to mess up regularly on (a b .c) types
+                               ; of lists.  Also printmacros have been added.
+
+(def $prdf
+  (lambda (l lmar rmar)
+    (prog nil
+;
+;                      - DNC - Here we try to fix the tendency to print a
+;                        thin column down the right margin by allowing it
+;                        to move back to the left if necessary.
+;
+         (cond ((and (>& lmar pparm1) (>& (flatc l (1+ pparm2)) pparm2))
+                (terpri $outport$)
+                (patom "; <<<<< start back on the left <<<<<" $outport$)
+                ($prdf l 5 0)
+                (terpri $outport$)
+                (patom "; >>>>> continue on the right >>>>>" $outport$)
+                (terpri $outport$)
+                (return nil)))
+          (tab lmar $outport$)
+     a    (cond ((and (dtpr l)
+                     (atom (car l))
+                     (or (and (get (car l) 'printmacro)
+                              (funcall (get (car l) 'printmacro)
+                                       l lmar rmar))
+                         (and (get (car l) 'printmacrochar)
+                              (printmacrochar (get (car l) 'printmacrochar)
+                                              l lmar rmar))))
+                (return nil))
+;
+;                              -DNC - a printmacro is a lambda (l lmar rmar)
+;                              attached to the atom.  If it returns nil then
+;                              we assume it did not apply and we continue.
+;                              Otherwise we assume it did the job.
+;
+                ((or (not (dtpr l))
+;                    (*** at the moment we just punt hunks etc)
+                     (and (atom (car l)) (atom (cdr l))))
+                 (return (printret l $outport$)))
+                ((<& (+ rmar (flatc l (charcnt $outport$)))
+                   (charcnt $outport$))
+                ;
+                ;      This is just a heuristic - if print can fit it in then figure that
+;      the printmacros won't hurt.  Note that despite the pretentions there
+;      is no guarantee that everything will fit in before rmar - for example
+;      atoms (and now even hunks) are just blindly printed.    - DNC
+;
+                 (printaccross l lmar rmar))
+                ((and ($patom1 lpar)
+                      (atom (car l))
+                      (not (atom (cdr l)))
+                      (not (atom (cddr l))))
+                 (prog (c)
+                       (printret (car l) $outport$)
+                       ($patom1 '" ")
+                       (setq c (nwritn $outport$))
+                  a    ($prd1 (cdr l) c)
+                       (cond
+                        ((not (atom (cdr (setq l (cdr l)))))
+                         (terpr $outport$)
+                         (go a)))))
+                (t
+                 (prog (c)
+                       (setq c (nwritn $outport$))
+                  a    ($prd1 l c)
+                       (cond
+                        ((not (atom (setq l (cdr l))))
+                         (terpr $outport$)
+                         (go a))))))
+     b    ($patom1 rpar))))
+
+(def $prd1
+  (lambda (l n)
+    (prog nil
+          ($prdf (car l)
+                 n
+                 (cond ((null (setq l (cdr l))) (|1+| rmar))
+                       ((atom l) (setq n nil) (plus 4 rmar (pntlen l)))
+                       (t rmar)))
+          (cond
+           ((null n) ($patom1 '" . ") (return (printret l $outport$))))
+;         (*** setting n is pretty disgusting)
+;         (*** the last arg to $prdf is the space needed for the suffix)
+;              ;Note that this is still not really right - if the prefix
+;              takes several lines one would like to use the old rmar 
+;              until the last line where the " . mumble)" goes.
+       )))
+
+; -DNC here's the printmacro for progs - it replaces some hackery that
+; used to be in the guts of $prdf.
+
+(def printprog
+  (lambda (l lmar rmar)
+    (prog (col)
+          (cond ((cdr (last l)) (return nil)))
+          (setq col (add1 lmar))
+          (princ '|(| $outport$)
+          (princ (car l) $outport$)
+          (princ '| | $outport$)
+          (print (cadr l) $outport$)
+          (mapc '(lambda (x)
+                        (cond ((atom x)
+                               (tab col $outport$)
+                               (print x $outport$))
+                          (t ($prdf x (+ lmar 6) rmar))))
+               (cddr l))
+          (princ '|)| $outport$)
+          (return t))))
+
+(putprop 'prog 'printprog 'printmacro)
+
+;;
+;;     simpler version which
+;;     should look nice for lambda's also.(inside mapcar's) -dhl
+;;
+(defun print-lambda (l lmar rmar)
+  (prog (col)
+       (cond ((cdr (last l)) (return nil)))
+       (setq col (add1 lmar))
+       (princ '|(| $outport$)
+              (princ (car l) $outport$)
+              (princ '| | $outport$)
+              (print (cadr l) $outport$)
+              (let ((c (cond ((eq (car l) 'lambda)
+                              8)
+                             (t 9))))
+                   (mapc '(lambda (x)
+                                  ($prdf x (+ lmar c) rmar))
+                         (cddr l)))
+              (princ '|)| $outport$)
+       (terpr $outport$)
+       (tab lmar $outport$)
+       (return t)))
+
+(putprop 'lambda 'print-lambda 'printmacro)
+(putprop 'nlambda 'print-lambda 'printmacro)
+
+; Here's the printmacro for def.  The original $prdf had some special code
+; for lambda and nlambda.
+
+(def printdef
+  (lambda (l lmar rmar)
+    (cond ((and (zerop lmar)           ; only if we're really printing a defn
+                (zerop rmar)
+                (cadr l)
+                (atom (cadr l))
+                (dtpr (caddr l))
+                (null (cdddr l))
+                (memq (caaddr l) '(lambda nlambda macro lexpr))
+                (null (cdr (last (caddr l)))))
+           (princ '|(| $outport$)
+           (princ 'def $outport$)
+           (princ '| | $outport$)
+           (princ (cadr l) $outport$)
+           (terpri $outport$)
+           (princ '|  (| $outport$)
+           (princ (caaddr l) $outport$)
+           (princ '| | $outport$)
+           (princ (cadaddr l) $outport$)
+           (terpri $outport$)
+           (mapc  '(lambda (x) ($prdf x 4 0)) (cddaddr l))
+           (princ '|))| $outport$)
+           t))))
+
+(putprop 'def 'printdef 'printmacro)
+
+; There's a version of this hacked into the printer (where it don't belong!)
+; Note that it must NOT apply to things like (quote a b).
+
+;
+; adding printmacrochar so that it can be used by other read macros
+; which create things of the form (tag lisp-expr) like quote does,
+; I know this is restrictive but it is helpful in the frl source. - dhl.
+;
+;
+
+(def printmacrochar
+  (lambda (macrochar l lmar rmar)
+    (cond ((or (null (cdr l)) (cddr l)) nil)
+          (t (princ macrochar $outport$) 
+             ($prdf (cadr l) (add1 lmar) rmar)
+             t))))
+
+(putprop 'quote '|'| 'printmacrochar)
+
+(def printaccross
+  (lambda (l lmar rmar)
+    (prog nil
+;         (*** this is needed to make sure the printmacros are executed)
+          (princ '|(| $outport$)
+     l:   (cond ((null l))
+                ((atom l) (princ '|. | $outport$) (princ l $outport$))
+                (t ($prdf (car l) (nwritn $outport$) rmar)
+                   (setq l (cdr l))
+                   (cond (l (princ '| | $outport$)))
+                   (go l:))))))
+
diff --git a/usr/src/ucb/lisp/lisplib/struct.l b/usr/src/ucb/lisp/lisplib/struct.l
new file mode 100644 (file)
index 0000000..b5ddc14
--- /dev/null
@@ -0,0 +1,1586 @@
+;;; -*- Mode:Lisp; Package:SI; Lowercase:True; Base:8 -*-
+;;;    ** (c) Copyright 1980 Massachusetts Institute of Technology **
+(setq rcs-struct-
+   "$Header: /usr/lib/lisp/RCS/struct.l,v 1.2 83/08/06 08:41:10 jkf Exp $")
+
+;The master copy of this file is in MC:ALAN;NSTRUCT >
+;The current Lisp machine copy is in AI:LISPM2;STRUCT >
+;The current Multics copy is in >udd>Mathlab>Bawden>defstruct.lisp
+
+;*****  READ THIS PLEASE!  *****
+;If you are thinking of munging anything in this file you might want
+;to consider finding me (ALAN) and asking me to mung it for you.
+;There is more than one copy of this file in the world (it runs in PDP10
+;and Multics MacLisp and on LispMachines) and whatever amazing
+;features you are considering adding might be usefull to those people
+;as well.  If you still cannot contain yourself long enough to find
+;me, AT LEAST send me a piece of mail describing what you did and why.
+;Thanks for reading this flame.
+;                                       Alan Bawden (ALAN@MC)
+
+;Things to fix:
+
+;For LispMachine:
+; :%P-LDB type (this is hard to do, punt for now.)
+
+;For Multics:
+; displacement is a problem (no displace)
+; nth, nthcdr don't exist there
+; ldb, dpb don't exist, so byte fields don't work without Mathlab macros
+; callable accessors don't work
+; dpb is needed at the user's compile time if he is using byte fields.
+
+#+Franz (environment-maclisp)
+
+(eval-when (compile)
+  (cond ((status feature ITS)
+        (load '|alan;lspenv init|))
+       ((status feature Multics)
+        (load '|>udd>Mathlab>Bawden>lspenv.lisp|))))
+
+#+PDP10
+(cond ((status nofeature noldmsg)
+       (terpri msgfiles)
+       (princ '#.(and (status feature PDP10)
+                     (maknam (nconc (exploden ";Loading DEFSTRUCT ")
+                                    (exploden (caddr (truename infile))))))
+             msgfiles)))
+
+#+Multics
+(declare (genprefix defstruct-internal-)
+        (macros t))
+
+#+Franz
+(declare (macros t))
+
+#M
+(eval-when (eval compile)
+  (setsyntax #/: (ascii #\space) nil))
+
+;; #+Franz
+;; (eval-when (eval compile)
+;;    (setsyntax #/: 'vseparator))             ; make :'s go away
+
+(eval-when (eval)
+  ;;So we may run the thing interpreted we need the simple
+  ;;defstruct that lives here:
+  (cond ((status feature ITS)
+        (load '|alan;struct initial|))
+       ((status feature Multics)
+        (load '|>udd>Mathlab>Bawden>initial_defstruct|))
+       ((status feature Franz)
+        (load 'structini.l))))
+
+(eval-when (compile)
+  ;;To compile the thing this probably is an old fasl: (!)
+  (cond ((status feature ITS)
+        (load '|alan;struct boot|))
+       ((status feature Multics)
+        (load '|>udd>Mathlab>Bawden>boot_defstruct|))
+       ((status feature Franz) ; This is only needed for bootstrapping
+        (cond ((and (null (getd 'defstruct))
+                    (not (probef
+                            (concat lisp-library-directory "//struct.o"))))
+               (load 'structini))))
+       ))
+
+#+Multics
+(defun nth (n l)
+  (do ((n n (1- n))
+       (l l (cdr l)))
+      ((zerop n) (car l))))
+
+#+Multics
+(defun nthcdr (n l)
+  (do ((n n (1- n))
+       (l l (cdr l)))
+      ((zerop n) l)))
+
+#+(or Franz Multics)
+(defun displace (x y)
+  (cond ((atom y)
+        (rplaca x 'progn)
+        (rplacd x (list y)))
+       (t
+        (rplaca x (car y))
+        (rplacd x (cdr y))))
+  x)
+
+;;; You might think you could use progn for this, but you can't!
+(defun defstruct-dont-displace (x y)
+  x    ;ignored
+  y)
+\f
+;;; Eval this before attempting incremental compilation
+(eval-when (eval compile)
+
+#+PDP10
+(defmacro append-symbols args
+  (do ((l (reverse args) (cdr l))
+       (x)
+       (a nil (if (or (atom x)
+                     (not (eq (car x) 'quote)))
+                 (if (null a)
+                     `(exploden ,x)
+                     `(nconc (exploden ,x) ,a))
+                 (let ((l (exploden (cadr x))))
+                   (cond ((null a) `',l)
+                         ((= 1 (length l)) `(cons ,(car l) ,a))
+                         (t `(append ',l ,a)))))))
+
+            ((null l) `(implode ,a))
+    (setq x (car l))))
+
+#+Multics
+(defmacro append-symbols args
+  `(make_atom (catenate . ,args)))
+
+#+LispM
+(defmacro append-symbols args
+  `(intern (string-append . ,args)))
+
+#+Franz
+(defmacro append-symbols (&rest args)
+   `(concat . ,args))
+   
+(defmacro defstruct-putprop (sym val ind)
+  `(push `(defprop ,,sym ,,val ,,ind) returns))
+
+(defmacro defstruct-put-macro (sym fcn)
+  #M `(defstruct-putprop ,sym ,fcn 'macro)
+  #+lispm
+    (setq fcn (if (and (not (atom fcn))
+                       (eq (car fcn) 'quote))
+                  `'(macro . ,(cadr fcn))
+                  `(cons 'macro ,fcn)))
+  #+Franz
+    (setq fcn (if (and (not (atom fcn))
+                      (eq (car fcn) 'quote))
+                 `'(macro (macroarg) (,(cadr fcn) macroarg))
+                 `(cons 'macro ,fcn)))   ;; probably incorrect
+                          
+  #Q `(push `(fdefine ',,sym ',,fcn t) returns)
+  #+Franz `(push `(def ,,sym ,,fcn) returns)
+  )
+
+(defmacro make-empty () `'%%defstruct-empty%%)
+
+(defmacro emptyp (x) `(eq ,x '%%defstruct-empty%%))
+\f
+;;;Here we must deal with the fact that error reporting works
+;;;differently everywhere!
+
+#+(or Franz PDP10)
+;;;first arg is ALWAYS a symbol or a quoted symbol:
+(defmacro defstruct-error (message &rest args)
+  (let* ((chars (nconc (exploden (if (atom message)
+                                    message
+                                    (cadr message)))
+                      '(#/.)))         ;"Bad frob" => "Bad frob."
+        (new-message
+         (maknam (if (null args)
+                     chars
+                     (let ((c (car chars)))    ;"Bad frob." => "-- bad frob."
+                       (or (< c #/A)
+                           (> c #/Z)
+                           (rplaca chars (+ c #o40)))
+                       (append '(#/- #/- #\space) chars))))))
+  `(error ',new-message
+         ,@(cond ((null args) `())
+                 ((null (cdr args)) `(,(car args)))
+                 (t `((list ,@args)))))))
+
+#+Multics
+;;;first arg is ALWAYS a string:
+(defmacro defstruct-error (message &rest args)
+  `(error ,(catenate "defstruct: "
+                    message
+                    (if (null args)
+                        "."
+                        ": "))
+         ,@(cond ((null args) `())
+                 ((null (cdr args)) `(,(car args)))
+                 (t `((list ,@args))))))
+
+#+LispM
+;;;first arg is ALWAYS a string:
+(defmacro defstruct-error (message &rest args)
+  `(ferror nil
+          ,(string-append message
+                          (if (null args)
+                              "."
+                              ":~@{ ~S~}"))
+          ,@args))
+
+);End of eval-when (eval compile)
+\f
+;;;If you mung the the ordering af any of the slots in this structure,
+;;;be sure to change the version slot and the definition of the function
+;;;get-defstruct-description.  Munging the defstruct-slot-description
+;;;structure should also cause you to change the version "number" in this manner.
+(defstruct (defstruct-description
+            (:type :list)
+            (:default-pointer description)
+            (:conc-name defstruct-description-)
+            (:alterant nil))
+  (version 'one)
+  type
+  (displace 'defstruct-dont-displace)
+  slot-alist
+  named-p
+  constructors
+  (default-pointer nil)
+  (but-first nil)
+  size
+  (property-alist nil)
+  ;;end of "expand-time" slots
+  name
+  include
+  (initial-offset 0)
+  (eval-when '(eval compile load))
+  alterant
+  (conc-name nil)
+  (callable-accessors #M nil #Q t)
+  (size-macro nil)
+  (size-symbol nil)
+  )
+
+(defun get-defstruct-description (name)
+  (let ((description (get name 'defstruct-description)))
+    (cond ((null description)
+          (defstruct-error
+            "A structure with this name has not been defined" name))
+         ((not (eq (defstruct-description-version) 'one))
+          (defstruct-error "The description of this structure is out of date,
+it should be recompiled using the current version of defstruct"
+                 name))
+         (t description))))
+
+;;;See note above defstruct-description structure before munging this one.
+(defstruct (defstruct-slot-description
+            (:type :list)
+            (:default-pointer slot-description)
+            (:conc-name defstruct-slot-description-)
+            (:alterant nil))
+  number
+  (ppss nil)
+  init-code
+  (type 'notype)
+  (property-alist nil)
+  ref-macro-name
+  )
+
+;;;Perhaps this structure wants a version slot too?
+(defstruct (defstruct-type-description
+            (:type :list)
+            (:default-pointer type-description)
+            (:conc-name defstruct-type-description-)
+            (:alterant nil))
+  ref-expander
+  ref-no-args
+  cons-expander
+  cons-flavor
+  (cons-keywords nil)
+  (named-type nil)
+  (overhead 0)
+  (defstruct-expander nil)
+  )
+\f
+;; (DEFSTRUCT (<name> . <options>) . <slots>) or (DEFSTRUCT <name> . <slots>)
+;;
+;; <options> is of the form (<option> <option> (<option> <val>) ...)
+;;
+;; <slots> is of the form (<slot> (<slot> <initial-value>) ...)
+;;
+;; Options:
+;;   :TYPE defaults to HUNK
+;;   :CONSTRUCTOR defaults to "MAKE-<name>"
+;;   :DEFAULT-POINTER defaults to empty (if no <val> given defaults to "<name>")
+;;   :CONC-NAME defaults to empty (if no <val> given defaults to "<name>-")
+;;   :SIZE-SYMBOL defaults to empty (if no <val> given defaults to "<name>-SIZE")
+;;   :SIZE-MACRO defaults to empty (if no <val> given defaults to "<name>-SIZE")
+;;   :ALTERANT defaults to "ALTER-<name>"
+;;   :BUT-FIRST must have a <val> given
+;;   :INCLUDE must have a <val> given
+;;   :PROPERTY (:property foo bar) gives the structure a foo property of bar.
+;;   :INITIAL-OFFSET can cause defstruct to skip over that many slots.
+;;   :NAMED takes no value.  Tries to make the structure a named type.
+;;   :CALLABLE-ACCESSORS defaults to T on the LispMachine, NIL elsewhere.
+;;   <type> any type name can be used without a <val> instead of saying (TYPE <type>)
+;;   <other> any symbol with a non-nil :defstruct-option property.  You say
+;;     (<other> <val>) and the effect is that of (:property <other> <val>)
+;;
+;; Properties used:
+;;   DEFSTRUCT-TYPE-DESCRIPTION each type has one, it is a type-description.
+;;   DEFSTRUCT-NAME each constructor, alterant and size macro has one, it is a name.
+;;   DEFSTRUCT-DESCRIPTION each name has one, it is a description (see below).
+;;   DEFSTRUCT-SLOT each accesor has one, it is of the form: (<name> . <slot>)
+;;   :DEFSTRUCT-OPTION if a symbol FOO has this property then it can be used as an
+;;     option giving the structure a FOO property of the value (which must be given).
+\f
+(defmacro defstruct (options &body items)
+  (let* ((description (defstruct-parse-options options))
+        (type-description (get (defstruct-description-type)
+                               'defstruct-type-description))
+        (name (defstruct-description-name))
+        (new-slots (defstruct-parse-items items description))
+        (returns nil))
+    (push `',name returns)
+    (or (null (defstruct-type-description-defstruct-expander))
+       (setq returns (append (funcall (defstruct-type-description-defstruct-expander)
+                                      description)
+                             returns)))
+    #Q (push `(record-source-file-name ',name) returns)
+    (defstruct-putprop name description 'defstruct-description)
+    (let ((alterant (defstruct-description-alterant))
+         (size-macro (defstruct-description-size-macro))
+         (size-symbol (defstruct-description-size-symbol)))
+      (cond (alterant
+            (defstruct-put-macro alterant 'defstruct-expand-alter-macro)
+            (defstruct-putprop alterant name 'defstruct-name)))
+      (cond (size-macro
+            (defstruct-put-macro size-macro 'defstruct-expand-size-macro)
+            (defstruct-putprop size-macro name 'defstruct-name)))
+      (cond (size-symbol
+            (push `(#M defvar #Q defconst #F setq ,size-symbol
+                       ,(+ (defstruct-description-size)
+                           (defstruct-type-description-overhead)))
+                  returns))))
+    (do cs (defstruct-description-constructors) (cdr cs) (null cs)
+       (defstruct-put-macro (caar cs) 'defstruct-expand-cons-macro)
+       (defstruct-putprop (caar cs) name 'defstruct-name))
+    `(eval-when ,(defstruct-description-eval-when)
+               ,.(defstruct-define-ref-macros new-slots description)
+               . ,returns)))
+\f
+(defun defstruct-parse-options (options)
+  (let ((name (if (atom options) options (car options)))
+       (type nil)
+       (constructors (make-empty))
+       (alterant (make-empty))
+       (included nil)
+       (named-p nil)
+       (description (make-defstruct-description)))
+    (setf (defstruct-description-name) name)
+    (do ((op) (val) (vals)
+        (options (if (atom options) nil (cdr options))
+                 (cdr options)))
+       ((null options))
+      (if (atom (setq op (car options)))
+         (setq vals nil)
+         (setq op (prog1 (car op) (setq vals (cdr op)))))
+      (setq val (if (null vals) (make-empty) (car vals)))
+  #Q AGAIN 
+      (selectq op
+       (:type
+        (if (emptyp val)
+            (defstruct-error
+              "The type option to defstruct must have a value given"
+              name))
+        (setq type val))
+       (:default-pointer
+        (setf (defstruct-description-default-pointer)
+              (if (emptyp val) name val)))
+       (:but-first
+        (if (emptyp val)
+            (defstruct-error
+              "The but-first option to defstruct must have a value given"
+              name))
+        (setf (defstruct-description-but-first) val))
+       (:conc-name
+        (setf (defstruct-description-conc-name)
+              (if (emptyp val)
+                  (append-symbols name '-)
+                  val)))
+       (:callable-accessors
+        (setf (defstruct-description-callable-accessors)
+              (if (emptyp val) t val)))
+       (:displace
+        (setf (defstruct-description-displace)
+              (cond ((or (emptyp val)
+                         (eq val 't))
+                     'displace)
+                    ((null val) 'defstruct-dont-displace)
+                    (t val))))
+       (:constructor
+        (cond ((null val)
+               (setq constructors nil))
+              (t
+               (and (emptyp val)
+                    (setq val (append-symbols 'make- name)))
+               (setq val (cons val (cdr vals)))
+               (if (emptyp constructors)
+                   (setq constructors (list val))
+                   (push val constructors)))))
+       (:alterant
+        (setq alterant val))
+       (:size-macro
+        (setf (defstruct-description-size-macro)
+              (if (emptyp val)
+                  (append-symbols name '-size)
+                  val)))
+       (:size-symbol
+        (setf (defstruct-description-size-symbol)
+              (if (emptyp val)
+                  (append-symbols name '-size)
+                  val)))
+       (:include
+        (and (emptyp val)
+             (defstruct-error
+               "The include option to defstruct requires a value"
+               name))
+        (setq included val)
+        (setf (defstruct-description-include) vals))
+       (:property
+        (push (cons (car vals) (if (null (cdr vals)) t (cadr vals)))
+              (defstruct-description-property-alist)))
+       (:named
+        (or (emptyp val)
+            (defstruct-error
+              "The named option to defstruct doesn't take a value" name))
+        (setq named-p t))
+       (:eval-when
+        (and (emptyp val)
+             (defstruct-error
+               "The eval-when option to defstruct requires a value"
+               name))
+        (setf (defstruct-description-eval-when) val))
+       (:initial-offset
+        (and (or (emptyp val)
+                 (not (fixp val)))
+             (defstruct-error
+               "The initial-offset option to defstruct requires a fixnum"
+               name))
+        (setf (defstruct-description-initial-offset) val))
+       (otherwise
+        (cond ((get op 'defstruct-type-description)
+               (or (emptyp val)
+                   (defstruct-error
+                     "defstruct type used as an option with a value"
+                     op 'in name))
+               (setq type op))
+              ((get op ':defstruct-option)
+               (push (cons op (if (emptyp val) t val))
+                     (defstruct-description-property-alist)))
+              (t
+               #Q (multiple-value-bind (new foundp)
+                                       (intern-soft op si:pkg-user-package)
+                    (or (not foundp)
+                        (eq op new)
+                        (progn (setq op new) (go AGAIN))))
+               (defstruct-error
+                 "defstruct doesn't understand this option"
+                 op 'in name))))))
+    (cond ((emptyp constructors)
+          (setq constructors
+                (list (cons (append-symbols 'make- name)
+                            nil)))))
+    (setf (defstruct-description-constructors) constructors)
+    (cond ((emptyp alterant)
+          (setq alterant
+                (append-symbols 'alter- name))))
+    (setf (defstruct-description-alterant) alterant)
+    (cond ((not (null type))
+          (let ((type-description
+                 (or (get type 'defstruct-type-description)
+                  #Q (multiple-value-bind
+                               (new foundp)
+                               (intern-soft type si:pkg-user-package)
+                       (and foundp
+                            (not (eq type new))
+                            (progn (setq type new)
+                                   (get type 'defstruct-type-description))))
+                     (defstruct-error
+                       "Unknown type in defstruct"
+                       type 'in name))))
+            (if named-p
+                (setq type
+                      (or (defstruct-type-description-named-type)
+                          (defstruct-error
+                           "There is no way to make this defstruct type named"
+                           type 'in name)))))))
+    (cond (included
+          (let ((d (get-defstruct-description included)))
+            (if (null type)
+                (setq type (defstruct-description-type d))
+                (or (eq type (defstruct-description-type d))
+                    (defstruct-error
+                      "defstruct types must agree for include option"
+                      included 'included-by name)))
+            (and named-p
+                 (not (eq type (defstruct-type-description-named-type
+                                 (or (get type 'defstruct-type-description)
+                                     (defstruct-error
+                                       "Unknown type in defstruct"
+                                       type 'in name 'including included)))))
+                 (defstruct-error
+                   "Included defstruct's type isn't a named type"
+                   included 'included-by name))))
+         ((null type)
+          (setq type
+            (cond (named-p
+                   #+PDP10 ':named-hunk
+                   #+Franz ':named-vector
+                   #+Multics ':named-list
+                   #+LispM ':named-array)
+                  (t
+                   #+PDP10 ':hunk
+                   #+Franz ':named-vector
+                   #+Multics ':list
+                   #+LispM ':array)))))
+    (let ((type-description (or (get type 'defstruct-type-description)
+                               (defstruct-error
+                                 "Undefined defstruct type"
+                                 type 'in name))))
+      (setf (defstruct-description-type) type)
+      (setf (defstruct-description-named-p)
+           (eq (defstruct-type-description-named-type) type)))
+    description))
+\f
+(defun defstruct-parse-items (items description)
+  (let ((name (defstruct-description-name))
+       (offset (defstruct-description-initial-offset))
+       (include (defstruct-description-include))
+       (o-slot-alist nil)
+       (conc-name (defstruct-description-conc-name)))
+    (or (null include)
+       (let ((d (get (car include) 'defstruct-description)))
+         (setq offset (+ offset (defstruct-description-size d))) 
+         (setq o-slot-alist
+               (subst nil nil (defstruct-description-slot-alist d)))
+         (do ((l (cdr include) (cdr l))
+              (it) (val))
+             ((null l))
+           (cond ((atom (setq it (car l)))
+                  (setq val (make-empty)))
+                 (t
+                  (setq val (cadr it))
+                  (setq it (car it))))
+           (let ((slot-description (cdr (assq it o-slot-alist))))
+             (and (null slot-description)
+                  (defstruct-error
+                    "Unknown slot in included defstruct"
+                    it 'in include 'included-by name))
+             (setf (defstruct-slot-description-init-code) val)))))
+    (do ((i offset (1+ i))
+        (l items (cdr l))
+        (slot-alist nil)
+        #+PDP10 (chars (exploden conc-name)))
+       ((null l)
+        (setq slot-alist (nreverse slot-alist))
+        (setf (defstruct-description-size) i)
+        (setf (defstruct-description-slot-alist)
+              (nconc o-slot-alist slot-alist))
+        slot-alist)
+      (cond ((atom (car l))
+            (push (defstruct-parse-one-field
+                    (car l) i nil nil conc-name #+PDP10 chars)
+                  slot-alist))
+           ((atom (caar l))
+            (push (defstruct-parse-one-field
+                    (caar l) i nil (cdar l) conc-name #+PDP10 chars)
+                  slot-alist))
+           (t
+            (do ll (car l) (cdr ll) (null ll)
+                (push (defstruct-parse-one-field
+                        (caar ll) i (cadar ll)
+                        (cddar ll) conc-name #+PDP10 chars)
+                      slot-alist)))))))
+
+(defun defstruct-parse-one-field (it number ppss rest conc-name #+PDP10 chars)
+  (let ((mname (if conc-name #+PDP10 (implode (append chars (exploden it)))
+                            #+Multics (make_atom (catenate conc-name it))
+                            #+Franz (concat conc-name it)
+                            #+LispM (intern (string-append conc-name it))
+                  it)))
+    (cons it (make-defstruct-slot-description
+              number number
+              ppss ppss
+              init-code (if (null rest) (make-empty) (car rest))
+              ref-macro-name mname))))
+\f
+(defun defstruct-define-ref-macros (new-slots description)
+  (let ((name (defstruct-description-name))
+       (returns nil))
+    (if (not (defstruct-description-callable-accessors))
+       (do ((l new-slots (cdr l))
+            (mname))
+           ((null l))
+         (setq mname (defstruct-slot-description-ref-macro-name (cdar l)))
+         (defstruct-put-macro mname 'defstruct-expand-ref-macro)
+         (defstruct-putprop mname (cons name (caar l)) 'defstruct-slot))
+       (let ((type-description
+               (get (defstruct-description-type)
+                    'defstruct-type-description)))
+         (let ((code (defstruct-type-description-ref-expander))
+               (n (defstruct-type-description-ref-no-args))
+               (but-first (defstruct-description-but-first))
+               (default-pointer (defstruct-description-default-pointer)))
+           (do ((args nil (cons (gensym) args))
+                (i n (1- i)))
+               ((< i 2)
+                ;;Last arg (if it exists) is name of structure,
+                ;; for documentation purposes.
+                (and (= i 1)
+                     (setq args (cons name args)))
+                (let ((body (cons (if but-first
+                                      `(,but-first ,(car args))
+                                      (car args))
+                                  (cdr args))))
+                  (and default-pointer
+                       (setq args `((,(car args) ,default-pointer)
+                                    &optional . ,(cdr args))))
+                  (setq args (reverse args))
+                  (setq body (reverse body))
+                  (do ((l new-slots (cdr l))
+                       (mname))
+                      ((null l))
+                    (setq mname (defstruct-slot-description-ref-macro-name
+                                  (cdar l)))
+                    #M ;;This must come BEFORE the defun. THINK!
+                    (defstruct-put-macro mname 'defstruct-expand-ref-macro)
+                    (let ((ref (lexpr-funcall
+                                 code
+                                 (defstruct-slot-description-number (cdar l))
+                                 description
+                                 body))
+                          (ppss (defstruct-slot-description-ppss (cdar l))))
+                      (push `(#+(or Franz Maclisp)
+                               defun #Q defsubst ,mname ,args
+                               ,(if (null ppss) ref `(ldb ,ppss ,ref)))
+                          returns))
+                    (defstruct-putprop mname
+                                       (cons name (caar l))
+                                       'defstruct-slot))))))))
+    returns))
+\f
+(defun defstruct-expand-size-macro (x)
+  (let ((description (get-defstruct-description (get (car x) 'defstruct-name))))
+    (let ((type-description (get (defstruct-description-type)
+                                'defstruct-type-description)))
+      (funcall (defstruct-description-displace)
+              x
+              (+ (defstruct-description-size)
+                 (defstruct-type-description-overhead))))))
+
+(defun defstruct-expand-ref-macro (x)
+  (let* ((pair (get (car x) 'defstruct-slot))
+        (description (get-defstruct-description (car pair)))
+        (type-description
+          (get (defstruct-description-type) 'defstruct-type-description))
+        (code (defstruct-type-description-ref-expander))
+        (n (defstruct-type-description-ref-no-args))
+        (args (reverse (cdr x)))
+        (nargs (length args))
+        (default (defstruct-description-default-pointer))
+        (but-first (defstruct-description-but-first)))
+    (cond ((= n nargs)
+          (and but-first
+               (rplaca args `(,but-first ,(car args)))))
+         ((and (= n (1+ nargs)) default)
+          (setq args (cons (if but-first
+                               `(,but-first ,default)
+                               default)
+                           args)))
+         (t
+          (defstruct-error
+            "Wrong number of args to an accessor macro" x)))
+    (let* ((slot-description 
+            (cdr (or (assq (cdr pair)
+                           (defstruct-description-slot-alist))
+                     (defstruct-error
+                       "This slot no longer exists in this structure"
+                       (cdr pair) 'in (car pair)))))
+           (ref (lexpr-funcall
+                  code
+                  (defstruct-slot-description-number)
+                  description
+                  (nreverse args)))
+           (ppss (defstruct-slot-description-ppss)))
+      (funcall (defstruct-description-displace)
+              x
+              (if (null ppss)
+                  ref
+                  `(ldb ,ppss ,ref))))))
+\f
+(defun defstruct-parse-setq-style-slots (l slots others x)
+  (do ((l l (cddr l))
+       (kludge (cons nil nil)))
+      ((null l) kludge)
+    (or (and (cdr l)
+            (symbolp (car l)))
+       (defstruct-error
+         "Bad argument list to constructor or alterant macro" x))
+    (defstruct-make-init-dsc kludge (car l) (cadr l) slots others x)))
+
+(defun defstruct-make-init-dsc (kludge name code slots others x)
+  (let ((p (assq name slots)))
+    (if (null p)
+       (if (memq name others)
+           (push (cons name code) (cdr kludge))
+           (defstruct-error
+             "Unknown slot to constructor or alterant macro" x))
+       (let* ((slot-description (cdr p))
+              (number (defstruct-slot-description-number))
+              (ppss (defstruct-slot-description-ppss))
+              (dsc (assoc number (car kludge))))
+         (cond ((null dsc)
+                (setq dsc (list* number nil (make-empty) 0 0 nil))
+                (push dsc (car kludge))))
+         (cond ((null ppss)
+                (setf (car (cddr dsc)) code)
+                (setf (cadr dsc) t))
+               (t (cond #-Franz
+                        ((and (numberp ppss) (numberp code))
+                         (setf (ldb ppss (cadr (cddr dsc))) -1)
+                         (setf (ldb ppss (caddr (cddr dsc))) code))
+                        (t
+                         (push (cons ppss code) (cdddr (cddr dsc)))))
+                  (or (eq t (cadr dsc))
+                      (push name (cadr dsc)))))))))
+
+(defun defstruct-code-from-dsc (dsc)
+  (let ((code (car (cddr dsc)))
+       (mask (cadr (cddr dsc)))
+       (bits (caddr (cddr dsc))))
+    (if (emptyp code)
+       (setq code bits)
+       (or (zerop mask)
+           (setq code (if (numberp code)
+                          (boole 7 bits (boole 2 mask code))
+                          (if (zerop (logand mask
+                                             (1+ (logior mask (1- mask)))))
+                              (let ((ss (haulong (boole 2 mask (1- mask)))))
+                                `(dpb ,(lsh bits (- ss))
+                                      ,(logior (lsh ss 6)
+                                               (logand #o77
+                                                       (- (haulong mask) ss)))
+                                      ,code))
+                              `(boole 7 ,bits (boole 2 ,mask ,code)))))))
+    (do l (cdddr (cddr dsc)) (cdr l) (null l)
+       (setq code `(dpb ,(cdar l) ,(caar l) ,code)))
+    code))
+\f
+(defun defstruct-expand-cons-macro (x)
+  (let* ((description (get-defstruct-description (get (car x) 'defstruct-name)))
+        (type-description (get (defstruct-description-type)
+                               'defstruct-type-description))
+        (slot-alist (defstruct-description-slot-alist))
+        (cons-keywords (defstruct-type-description-cons-keywords))
+        inits kludge
+        (constructor-description 
+          (cdr (or (assq (car x) (defstruct-description-constructors))
+                   (defstruct-error
+                     "This constructor is no longer defined for this structure"
+                     (car x) 'in (defstruct-description-name)))))
+        (aux nil)
+        (aux-init nil))
+     (if (null constructor-description)
+        (setq kludge (defstruct-parse-setq-style-slots (cdr x)
+                                                       slot-alist
+                                                       cons-keywords
+                                                       x))
+        (prog (args l)
+              (setq kludge (cons nil nil))
+              (setq args (cdr x))
+              (setq l (car constructor-description))
+            R (cond ((null l)
+                     (if (null args)
+                         (return nil)
+                         (go barf-tma)))
+                    ((atom l) (go barf))
+                    ((eq (car l) '&optional) (go O))
+                    ((eq (car l) '&rest) (go S))
+                    ((eq (car l) '&aux) (go A))
+                    ((null args) (go barf-tfa)))
+              (defstruct-make-init-dsc kludge
+                                       (pop l)
+                                       (pop args)
+                                       slot-alist
+                                       cons-keywords
+                                       x)
+              (go R)
+            O (and (null args) (go OD))
+              (pop l)
+              (cond ((null l) (go barf-tma))
+                    ((atom l) (go barf))
+                    ((eq (car l) '&optional) (go barf))
+                    ((eq (car l) '&rest) (go S))
+                    ((eq (car l) '&aux) (go barf-tma)))
+              (defstruct-make-init-dsc kludge
+                                       (if (atom (car l)) (car l) (caar l))
+                                       (pop args)
+                                       slot-alist
+                                       cons-keywords
+                                       x)
+              (go O)
+           OD (pop l)
+              (cond ((null l) (return nil))
+                    ((atom l) (go barf))
+                    ((eq (car l) '&optional) (go barf))
+                    ((eq (car l) '&rest) (go S))
+                    ((eq (car l) '&aux) (go A)))
+              (or (atom (car l))
+                  (defstruct-make-init-dsc kludge
+                                           (caar l)
+                                           (cadar l)
+                                           slot-alist
+                                           cons-keywords
+                                           x))
+              (go OD)
+            S (and (atom (cdr l)) (go barf))
+              (defstruct-make-init-dsc kludge
+                                       (cadr l)
+                                       `(list . ,args)
+                                       slot-alist
+                                       cons-keywords
+                                       x)
+              (setq l (cddr l))
+              (and (null l) (return nil))
+              (and (atom l) (go barf))
+              (or (eq (car l) '&aux) (go barf))
+            A (pop l)
+              (cond ((null l) (return nil))
+                    ((atom l) (go barf))
+                    ((atom (car l))
+                     (push (car l) aux)
+                     (push (make-empty) aux-init))
+                    (t
+                     (push (caar l) aux)
+                     (push (cadar l) aux-init)))
+              (go A)
+         barf (defstruct-error
+                "Bad format for defstruct constructor arglist"
+                `(,(car x) . ,(car constructor-description)))
+      barf-tfa (defstruct-error "Too few arguments to constructor macro" x)
+      barf-tma (defstruct-error "Too many arguments to constructor macro" x)))
+     (do l slot-alist (cdr l) (null l)
+        (let* ((name (caar l))
+               (slot-description (cdar l))
+               (code (do ((aux aux (cdr aux))
+                          (aux-init aux-init (cdr aux-init)))
+                         ((null aux) (defstruct-slot-description-init-code))
+                       (and (eq name (car aux)) (return (car aux-init)))))
+               (ppss (defstruct-slot-description-ppss)))
+          (or (and (emptyp code) (null ppss))
+              (let* ((number (defstruct-slot-description-number))
+                     (dsc (assoc number (car kludge))))
+                (cond ((null dsc)
+                       (setq dsc (list* number nil (make-empty) 0 0 nil))
+                       (push dsc (car kludge))))
+                (cond ((emptyp code))
+                      ((eq t (cadr dsc)))
+                      ((null ppss)
+                       (and (emptyp (car (cddr dsc)))
+                            (setf (car (cddr dsc)) code)))
+                      ((memq name (cadr dsc)))
+                      #-Franz
+                      ((and (numberp ppss) (numberp code))
+                       (setf (ldb ppss (cadr (cddr dsc))) -1)
+                       (setf (ldb ppss (caddr (cddr dsc))) code))
+                      (t
+                       (push (cons ppss code) (cdddr (cddr dsc)))))))))
+     (selectq (defstruct-type-description-cons-flavor)
+             (:list
+              (do ((l nil (cons nil l))
+                   (i (defstruct-description-size) (1- i)))
+                  ((= i 0) (setq inits l)))
+              (do l (car kludge) (cdr l) (null l)
+                  (setf (nth (caar l) inits)
+                        (defstruct-code-from-dsc (car l)))))
+             (:alist
+              (setq inits (car kludge))
+              (do l inits (cdr l) (null l)
+                  (rplacd (car l) (defstruct-code-from-dsc (car l)))))
+             (otherwise
+              (defstruct-error
+                "Unknown flavor to constructor macro expander"
+                (defstruct-description-type))))
+     (funcall (defstruct-description-displace)
+             x (funcall (defstruct-type-description-cons-expander)
+                        inits description (cdr kludge)))))
+\f
+(defun defstruct-expand-alter-macro (x)
+  (let* ((description (get-defstruct-description (get (car x) 'defstruct-name)))
+        (type-description (get (defstruct-description-type)
+                               'defstruct-type-description))
+        (ref-code (defstruct-type-description-ref-expander)))
+    (or (= 1 (defstruct-type-description-ref-no-args))
+       (defstruct-error
+         "Alterant macros cannot handle this defstruct type"
+         (defstruct-description-type)))
+    (do ((l (car (defstruct-parse-setq-style-slots 
+                  (cddr x)
+                  (defstruct-description-slot-alist)
+                  nil
+                  x))
+           (cdr l))
+        (but-first (defstruct-description-but-first))
+        (body nil)
+        (var (gensym))
+        (vars nil)
+        (vals nil))
+       ((null l)
+        (funcall (defstruct-description-displace)
+                 x
+                 `((lambda (,var) 
+                     . ,(if (null vars)
+                            body
+                            `(((lambda ,vars . ,body) . ,vals))))
+                   ,(if but-first
+                        `(,but-first ,(cadr x))
+                        (cadr x)))))
+      (let ((ref (funcall ref-code (caar l) description var)))
+       (and (emptyp (car (cddr (car l))))
+            (setf (car (cddr (car l))) ref))
+       (let ((code (defstruct-code-from-dsc (car l))))
+         (if (null (cdr l))
+             (push `(setf ,ref ,code) body)
+             (let ((sym (gensym)))
+               (push `(setf ,ref ,sym) body)
+               (push sym vars)
+               (push code vals))))))))
+\f
+(defmacro defstruct-define-type (type . options)
+  (do ((options options (cdr options))
+       (op) (args)
+       (type-description (make-defstruct-type-description))
+       (cons-expander nil)
+       (ref-expander nil)
+       (defstruct-expander nil))
+      ((null options)
+       (or cons-expander
+          (defstruct-error "No cons option in defstruct-define-type" type))
+       (or ref-expander
+          (defstruct-error "No ref option in defstruct-define-type" type))
+       `(progn 'compile
+              ,cons-expander
+              ,ref-expander
+              ,@(and defstruct-expander (list defstruct-expander))
+              (defprop ,type ,type-description defstruct-type-description)))
+    (cond ((atom (setq op (car options)))
+          (setq args nil))
+         (t
+          (setq args (cdr op))
+          (setq op (car op))))
+#Q AGAIN
+    (selectq op
+      (:cons
+        (or (> (length args) 2)
+           (defstruct-error
+             "Bad cons option in defstruct-define-type"
+             (car options) 'in type))
+       (let ((n (length (car args)))
+             (name (append-symbols type '-defstruct-cons)))
+         (or (= n 3)
+             (defstruct-error
+               "Bad cons option in defstruct-define-type"
+               (car options) 'in type))
+         (setf (defstruct-type-description-cons-flavor)
+               #-LispM (cadr args)
+               #+LispM (intern (string (cadr args)) si:pkg-user-package))
+         (setf (defstruct-type-description-cons-expander) name)
+         (setq cons-expander `(defun ,name ,(car args)
+                                . ,(cddr args)))))
+      (:ref
+        (or (> (length args) 1)
+           (defstruct-error
+             "Bad ref option in defstruct-define-type"
+             (car options) 'in type))
+       (let ((n (length (car args)))
+             (name (append-symbols type '-defstruct-ref)))
+         (or (> n 2)
+             (defstruct-error
+               "Bad ref option in defstruct-define-type"
+               (car options) 'in type))
+         (setf (defstruct-type-description-ref-no-args) (- n 2))
+         (setf (defstruct-type-description-ref-expander) name)
+         (setq ref-expander `(defun ,name ,(car args)
+                               . ,(cdr args)))))
+      (:overhead
+        (setf (defstruct-type-description-overhead)
+             (if (null args)
+                 (defstruct-error
+                   "Bad option to defstruct-define-type"
+                   (car options) 'in type)
+                 (car args))))
+      (:named
+        (setf (defstruct-type-description-named-type)
+             (if (null args)
+                 type
+                 (car args))))
+      (:keywords
+        (setf (defstruct-type-description-cons-keywords) args))
+      (:defstruct
+        (or (> (length args) 1)
+           (defstruct-error
+             "Bad defstruct option in defstruct-define-type"
+             (car options) 'in type))
+       (let ((name (append-symbols type '-defstruct-expand)))
+         (setf (defstruct-type-description-defstruct-expander) name)
+         (setq defstruct-expander `(defun ,name . ,args))))
+      (otherwise
+       #Q (multiple-value-bind (new foundp)
+             (intern-soft op si:pkg-user-package)
+           (or (not foundp)
+               (eq op new)
+               (progn (setq op new) (go AGAIN))))
+       (defstruct-error
+        "Unknown option to defstruct-define-type"
+        (car options) 'in type)))))
+\f
+#Q
+(defprop :make-array t :defstruct-option)
+
+(defstruct-define-type :array
+  #Q (:named :named-array)
+  #Q (:keywords :make-array)
+  (:cons
+    (arg description etc) :alist
+    #M etc             ;ignored in MacLisp
+    #F etc             ;ignored in MacLisp
+    #Q (lispm-array-for-defstruct arg #'(lambda (v a i) `(aset ,v ,a ,i))
+                                 description etc nil nil nil 1)
+    #M (maclisp-array-for-defstruct arg description 't)
+    #F (maclisp-array-for-defstruct arg description 't))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    #M `(arraycall t ,arg ,n)
+    #F `(arraycall t ,arg ,n)
+    #Q `(aref ,arg ,n)))
+
+#Q
+(defstruct-define-type :named-array
+  (:keywords :make-array)
+  :named (:overhead 1)
+  (:cons
+    (arg description etc) :alist
+    (lispm-array-for-defstruct arg #'(lambda (v a i) `(aset ,v ,a ,(1+ i)))
+                              description etc nil t nil 1))
+  (:ref (n description arg)
+       description     ;ignored
+       `(aref ,arg ,(1+ n))))
+
+(defstruct-define-type :fixnum-array
+  #Q (:keywords :make-array)
+  (:cons
+    (arg description etc) :alist
+    #M etc             ;ignored in MacLisp
+    #F etc             ;ignored in MacLisp
+    #Q (lispm-array-for-defstruct arg #'(lambda (v a i) `(aset ,v ,a ,i))
+                                 description etc 'art-32b nil nil 1)
+    #M (maclisp-array-for-defstruct arg description 'fixnum)
+    #F (maclisp-array-for-defstruct arg description 'fixnum))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    #M `(arraycall fixnum ,arg ,n)
+    #F `(arraycall fixnum ,arg ,n)
+    #Q `(aref ,arg ,n)))
+
+(defstruct-define-type :flonum-array
+  #Q (:keywords :make-array)
+  (:cons
+    (arg description etc) :alist
+    #M etc             ;ignored in MacLisp
+    #F etc             ;ignored in MacLisp
+    #Q (lispm-array-for-defstruct arg #'(lambda (v a i) `(aset ,v ,a ,i))
+                                 description etc 'art-float nil nil 1)
+    #M (maclisp-array-for-defstruct arg description 'flonum)
+    #F (maclisp-array-for-defstruct arg description 'flonum))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    #M `(arraycall flonum ,arg ,n)
+    #F `(arraycall flonum ,arg ,n)
+    #Q `(aref ,arg ,n)))
+
+#M
+(defstruct-define-type :un-gc-array
+  (:cons
+    (arg description etc) :alist
+    etc                        ;ignored
+    (maclisp-array-for-defstruct arg description 'nil))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    `(arraycall nil ,arg ,n)))
+
+#Q
+(defstruct-define-type :array-leader
+  (:named :named-array-leader)
+  (:keywords :make-array)
+  (:cons
+    (arg description etc) :alist
+    (lispm-array-for-defstruct arg #'(lambda (v a i)
+                                      `(store-array-leader ,v ,a ,i))
+                              description etc nil nil t 1))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    `(array-leader ,arg ,n)))
+
+#Q
+(defstruct-define-type :named-array-leader
+  (:keywords :make-array)
+  :named (:overhead 1)
+  (:cons
+    (arg description etc) :alist
+    (lispm-array-for-defstruct
+      arg
+      #'(lambda (v a i)
+         `(store-array-leader ,v ,a ,(if (zerop i)
+                                         0
+                                         (1+ i))))
+      description etc nil t t 1))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    (if (zerop n)
+       `(array-leader ,arg 0)
+       `(array-leader ,arg ,(1+ n)))))
+
+#Q
+(defprop :times t :defstruct-option)
+
+#Q
+(defstruct-define-type :grouped-array
+  (:keywords :make-array :times)
+  (:cons
+    (arg description etc) :alist
+    (lispm-array-for-defstruct
+      arg
+      #'(lambda (v a i) `(aset ,v ,a ,i))
+      description etc nil nil nil
+      (or (cdr (or (assq ':times etc)
+                  (assq ':times (defstruct-description-property-alist))))
+         1)))
+  (:ref
+    (n description index arg)
+    description                ;ignored
+    (cond ((numberp index)
+          `(aref ,arg ,(+ n index)))
+         ((zerop n)
+          `(aref ,arg ,index))
+         (t `(aref ,arg (+ ,n ,index))))))
+\f
+#Q
+(defun lispm-array-for-defstruct (arg cons-init description etc type named-p leader-p times)
+  (let ((p (cons nil nil))
+       (no-op 'nil))
+    (defstruct-grok-make-array-args
+      (cdr (assq ':make-array (defstruct-description-property-alist)))
+      p)
+    (defstruct-grok-make-array-args
+      (cdr (assq ':make-array etc))
+      p)
+    (and type (putprop p type ':type))
+    (and named-p (putprop p `',(defstruct-description-name) ':named-structure-symbol))
+    (putprop p
+            (let ((size (if named-p
+                            (1+ (defstruct-description-size))
+                            (defstruct-description-size))))
+              (if (numberp times)
+                  (* size times)
+                  `(* ,size ,times)))       
+            (if leader-p ':leader-length ':dimensions))
+    (or leader-p
+       (let ((type (get p ':type)))
+         (or (atom type)
+             (not (eq (car type) 'quote))
+             (setq type (cadr type)))
+         (caseq type
+           ((nil art-q art-q-list))
+           ((art-32b art-16b art-8b art-4b art-2b art-1b art-string) (setq no-op '0))
+           ((art-float) (setq no-op '0.0))
+           (t (setq no-op (make-empty))))))
+    (do ((creator
+          (let ((dims (remprop p ':dimensions)))
+            (do l (cdr p) (cddr l) (null l)
+                (rplaca l `',(car l)))
+            `(make-array ,(if (null dims) 0 (car dims)) ,@(cdr p))))
+        (var (gensym))
+        (set-ups nil (if (equal (cdar l) no-op)
+                         set-ups
+                         (cons (funcall cons-init (cdar l) var (caar l))
+                               set-ups)))
+        (l arg (cdr l)))
+       ((null l)
+        (if set-ups
+            `((lambda (,var)
+                ,@(nreverse set-ups)
+                ,var)
+              ,creator)
+            creator)))))
+
+#Q
+(defun defstruct-grok-make-array-args (args p)
+  (let ((nargs (length args)))
+    (if (and (not (> nargs 7))
+            (or (oddp nargs)
+                (do ((l args (cddr l)))
+                    ((null l) nil)
+                  (or (memq (car l) '(:area :type :displaced-to :leader-list
+                                      :leader-length :displaced-index-offset
+                                      :named-structure-symbol :dimensions
+                                      :length))
+                      (return t)))))
+       (do ((l args (cdr l))
+            (keylist '(:area :type :dimensions :displaced-to :old-leader-length-or-list
+                       :displaced-index-offset :named-structure-symbol)
+                     (cdr keylist)))
+           ((null l)
+            (and (boundp 'compiler:compiler-warnings-context)
+                 (boundp 'compiler:last-error-function)
+                 (not (null compiler:compiler-warnings-context))
+                 (compiler:barf args '|-- old style :MAKE-ARRAY constructor keyword argument|
+                                'compiler:warn))
+            p)
+         (putprop p (car l) (car keylist)))
+       (do ((l args (cddr l)))
+           ((null l) p)
+         (if (or (null (cdr l))
+                 (not (memq (car l) '(:area :type :displaced-to :leader-list
+                                      :leader-length :displaced-index-offset
+                                      :named-structure-symbol :dimensions
+                                      :length))))
+             (defstruct-error
+               "defstruct can't grok these make-array arguments"
+               args))
+         (putprop p
+                  (cadr l)
+                  (if (eq (car l) ':length)
+                      ':dimensions
+                      (car l)))))))
+
+#+(or Franz Maclisp)
+(defun maclisp-array-for-defstruct (arg description type)
+  (do ((creator `(array nil ,type ,(defstruct-description-size)))
+       (var (gensym))
+       (no-op (caseq type
+               (fixnum 0)
+               (flonum 0.0)
+               ((t nil) nil)))
+       (set-ups nil (if (equal (cdar l) no-op)
+                       set-ups
+                       (cons `(store (arraycall ,type ,var ,(caar l))
+                                     ,(cdar l))
+                             set-ups)))
+       (l arg (cdr l)))
+      ((null l)
+       (if set-ups
+          `((lambda (,var)
+              ,@(nreverse set-ups)
+              ,var)
+            ,creator)
+          creator))))
+\f
+#+PDP10
+(defprop :sfa-function t :defstruct-option)
+
+#+PDP10
+(defprop :sfa-name t :defstruct-option)
+
+#+PDP10
+(defstruct-define-type :sfa
+  (:keywords :sfa-function :sfa-name)
+  (:cons
+    (arg description etc) :alist
+    (do ((creator `(sfa-create ,(or (cdr (or (assq ':sfa-function etc)
+                                            (assq ':sfa-function (defstruct-description-property-alist))))
+                                    `',(defstruct-description-name))
+                              ,(defstruct-description-size)
+                              ,(or (cdr (or (assq ':sfa-name etc)
+                                            (assq ':sfa-name (defstruct-description-property-alist))))
+                                   `',(defstruct-description-name))))
+        (l arg (cdr l))
+        (var (gensym))
+        (set-ups nil (if (null (cdar l))
+                         set-ups
+                         (cons `(sfa-store ,var ,(caar l)
+                                           ,(cdar l))
+                               set-ups))))
+       ((null l)
+        (if set-ups
+            `((lambda (,var)
+                ,@(nreverse set-ups)
+                ,var)
+              ,creator)
+            creator))))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    `(sfa-get ,arg ,n)))
+\f
+#+(or Franz PDP10)
+(defstruct-define-type :hunk
+  (:named :named-hunk)
+  (:cons
+    (arg description etc) :list
+    description                ;ignored
+    etc                        ;ignored
+    (if arg
+       #+PDP-10 `(hunk . ,(nconc (cdr arg) (ncons (car arg))))
+       #+Franz `(hunk . ,arg)
+       (defstruct-error "No slots in hunk type defstruct")))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    `(cxr ,n ,arg)))
+
+#+(or Franz PDP10)
+(defstruct-define-type :named-hunk
+  :named (:overhead 1)
+  (:cons
+    (arg description etc) :list
+    etc                        ;ignored
+    (if arg
+       #+PDP-10 `(hunk ',(defstruct-description-name)
+              . ,(nconc (cdr arg) (ncons (car arg))))
+       #+Franz `(hunk ',(defstruct-description-name)
+                      . ,arg)
+       `(hunk ',(defstruct-description-name) nil)))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    (cond #+PDP-10 ((= n 0) `(cxr 0 ,arg))
+         (t `(cxr ,(1+ n) ,arg)))))
+
+#+(or Franz PDP10 NIL )
+(defstruct-define-type :vector
+   #+Franz
+   (:named :named-vector)
+   (:cons
+      (arg description etc) :list
+      description              ;ignored
+      etc                      ;ignored
+      `(vector ,@arg))
+   (:ref
+      (n description arg)
+      description              ;ignored
+      `(vref ,arg ,n)))
+
+#+Franz
+(defstruct-define-type :named-vector
+   :named
+  (:cons
+    (arg description etc) :list
+    description                ;ignored
+    etc                        ;ignored
+    `(let ((nv (vector ,@arg)))
+       (vsetprop nv ',(defstruct-description-name))
+       nv))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    `(vref ,arg ,n)))
+\f
+(defstruct-define-type :list
+  (:named :named-list)
+  (:cons
+    (arg description etc) :list
+    description                ;ignored
+    etc                        ;ignored
+    `(list . ,arg))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    #+Multics `(,(let ((i (\ n 4)))
+                  (cond ((= i 0) 'car)
+                        ((= i 1) 'cadr)
+                        ((= i 2) 'caddr)
+                        (t 'cadddr)))
+               ,(do ((a arg `(cddddr ,a))
+                     (i (// n 4) (1- i)))
+                    ((= i 0) a)))
+    #-Multics `(nth ,n ,arg)))
+
+(defstruct-define-type :named-list
+  :named (:overhead 1)
+  (:cons
+    (arg description etc) :list
+    etc                        ;ignored
+    `(list ',(defstruct-description-name) . ,arg))
+  (:ref
+    (n description arg)
+    description                ;ignored
+    #+Multics `(,(let ((i (\ (1+ n) 4)))
+                  (cond ((= i 0) 'car)
+                        ((= i 1) 'cadr)
+                        ((= i 2) 'caddr)
+                        (t 'cadddr)))
+               ,(do ((a arg `(cddddr ,a))
+                     (i (// (1+ n) 4) (1- i)))
+                    ((= i 0) a)))
+    #-Multics `(nth ,(1+ n) ,arg)))
+\f
+(defstruct-define-type :list*
+  (:cons
+    (arg description etc) :list
+    description                ;ignored
+    etc                        ;ignored
+    `(list* . ,arg))
+  (:ref
+    (n description arg)
+    (let ((size (1- (defstruct-description-size))))
+      #+Multics (do ((a arg `(cddddr ,a))
+                    (i (// n 4) (1- i)))
+                   ((= i 0)
+                    (let* ((i (\ n 4))
+                           (a (cond ((= i 0) a)
+                                    ((= i 1) `(cdr ,a))
+                                    ((= i 2) `(cddr ,a))
+                                    (t `(cdddr ,a)))))
+                      (if (< n size) `(car ,a) a))))
+      #-Multics (if (< n size)
+                   `(nth ,n ,arg)
+                   `(nthcdr ,n ,arg))))
+  (:defstruct (description)
+    (and (defstruct-description-include)
+        (defstruct-error
+          "Structure of type list* cannot include another"
+          (defstruct-description-name)))
+    nil))
+
+(defstruct-define-type :tree
+  (:cons
+    (arg description etc) :list
+    etc                        ;ignored
+    (if (null arg) (defstruct-error
+                    "defstruct cannot make an empty tree"
+                    (defstruct-description-name)))
+    (make-tree-for-defstruct arg (defstruct-description-size)))
+  (:ref
+    (n description arg)
+    (do ((size (defstruct-description-size))
+        (a arg)
+        (tem))
+       (())
+      (cond ((= size 1) (return a))
+           ((< n (setq tem (// size 2)))
+            (setq a `(car ,a))
+            (setq size tem))
+           (t (setq a `(cdr ,a))
+              (setq size (- size tem))
+              (setq n (- n tem))))))
+  (:defstruct (description)
+    (and (defstruct-description-include)
+        (defstruct-error
+          "Structure of type tree cannot include another"
+          (defstruct-description-name)))
+    nil))
+
+(defun make-tree-for-defstruct (arg size)
+       (cond ((= size 1) (car arg))
+            ((= size 2) `(cons ,(car arg) ,(cadr arg)))
+            (t (do ((a (cdr arg) (cdr a))
+                    (m (// size 2))
+                    (n (1- (// size 2)) (1- n)))
+                   ((zerop n)
+                    `(cons ,(make-tree-for-defstruct arg m)
+                           ,(make-tree-for-defstruct a (- size m))))))))
+
+(defstruct-define-type :fixnum
+  (:cons
+    (arg description etc) :list
+    etc                        ;ignored
+    (and (or (null arg)
+            (not (null (cdr arg))))
+        (defstruct-error
+          "Structure of type fixnum must have exactly 1 slot to be constructable"
+          (defstruct-description-name)))
+    (car arg))
+  (:ref
+    (n description arg)
+    n                  ;ignored
+    description                ;ignored
+    arg))
+\f
+#+Multics
+(defprop :external-ptr t :defstruct-option)
+
+#+Multics
+(defstruct-define-type :external
+  (:keywords :external-ptr)
+  (:cons (arg description etc) :alist
+        (let ((ptr (cdr (or (assq ':external-ptr etc)
+                            (assq ':external-ptr
+                                  (defstruct-description-property-alist))
+                            (defstruct-error
+                              "No pointer given for external array"
+                              (defstruct-description-name))))))
+          (do ((creator `(array nil external ,ptr ,(defstruct-description-size)))
+               (var (gensym))
+               (alist arg (cdr alist))
+               (inits nil (cons `(store (arraycall fixnum ,var ,(caar alist))
+                                        ,(cdar alist))
+                                inits)))
+              ((null alist)
+               (if (null inits)
+                   creator
+                   `((lambda (,var) ,.inits ,var)
+                     ,creator))))))
+  (:ref (n description arg)
+       description     ;ignored
+       `(arraycall fixnum ,arg ,n)))
+\f
+(defvar *defstruct-examine&deposit-arg*)
+
+(defun defstruct-examine (*defstruct-examine&deposit-arg*
+                         name slot-name)
+  (eval (list (defstruct-slot-description-ref-macro-name
+               (defstruct-examine&deposit-find-slot-description
+                 name slot-name))
+             '*defstruct-examine&deposit-arg*)))
+
+(defvar *defstruct-examine&deposit-val*)
+
+(defun defstruct-deposit (*defstruct-examine&deposit-val*
+                         *defstruct-examine&deposit-arg*
+                         name slot-name)
+  (eval (list 'setf
+             (list (defstruct-slot-description-ref-macro-name
+                    (defstruct-examine&deposit-find-slot-description
+                      name slot-name))
+                   '*defstruct-examine&deposit-arg*)
+             '*defstruct-examine&deposit-val*)))
+
+#Q
+(defun defstruct-get-locative (*defstruct-examine&deposit-arg*
+                              name slot-name)
+  (let ((slot-description (defstruct-examine&deposit-find-slot-description
+                           name slot-name)))
+    (or (null (defstruct-slot-description-ppss))
+       (defstruct-error
+         "You cannot get a locative to a byte field"
+         slot-name 'in name))
+    (eval (list 'locf
+               (list (defstruct-slot-description-ref-macro-name)
+                     '*defstruct-examine&deposit-arg*)))))
+
+(defun defstruct-examine&deposit-find-slot-description (name slot-name)
+  (let ((description (get-defstruct-description name)))
+    (let ((slot-description
+           (cdr (or (assq slot-name (defstruct-description-slot-alist))
+                    (defstruct-error
+                      "No such slot in this structure"
+                      slot-name 'in name))))
+         (type-description
+           (or (get (defstruct-description-type) 'defstruct-type-description)
+               (defstruct-error
+                 "Undefined defstruct type"
+                 (defstruct-description-type)))))
+      (or (= (defstruct-type-description-ref-no-args) 1)
+         (defstruct-error
+           "defstruct-examine and defstruct-deposit cannot handle structures of this type"
+           (defstruct-description-type)))
+      slot-description)))
+\f
+#+PDP10
+(defprop defstruct
+        #.(and (status feature PDP10)
+               (caddr (truename infile)))
+        version)
+
+(sstatus feature defstruct)
diff --git a/usr/src/ucb/lisp/lisplib/toplevel.l b/usr/src/ucb/lisp/lisplib/toplevel.l
new file mode 100644 (file)
index 0000000..fad29c2
--- /dev/null
@@ -0,0 +1,480 @@
+(setq rcs-toplevel-
+   "$Header: toplevel.l,v 1.5 83/09/04 10:20:41 jkf Exp $")
+
+;;
+;; toplevel.l                          -[Mon Aug 22 13:24:43 1983 by jkf]-
+;;
+;;  toplevel read eval print loop
+;;
+
+
+; special atoms:
+(declare (special debug-level-count break-level-count
+                 errlist tpl-errlist user-top-level
+                 franz-not-virgin piport ER%tpl ER%all
+                 $ldprint evalhook funcallhook
+                 franz-minor-version-number
+                 top-level-init
+                 top-level-prompt top-level-read
+                 top-level-eval top-level-print
+                 top-level-eof * ** *** + ++ +++ ^w)
+         (localf autorunlisp cvtsearchpathtolist)
+        (macros t))
+
+(setq top-level-eof (gensym 'Q)
+      tpl-errlist nil
+      errlist nil
+      user-top-level nil
+      top-level-init nil
+      top-level-prompt nil
+      top-level-read  nil
+      top-level-eval nil
+      top-level-print nil)
+
+;--- initialization, prompt, read, eval, and print functions are
+; user-selectable by just assigning another value to top-level-init,
+; top-level-prompt, top-level-read, top-level-eval, and top-level-print.
+;
+(defmacro top-init nil
+   '(cond ((and top-level-init
+               (getd top-level-init))
+          (funcall top-level-init))
+         (t (cond ((not (autorunlisp))
+                   (patom (status version))
+                   ; franz-minor-version-number defined in version.l
+                   (cond ((boundp 'franz-minor-version-number)
+                          (patom franz-minor-version-number)))
+                   (terpr)
+                   (read-in-lisprc-file))))))
+     
+(defmacro top-prompt nil
+   `(cond ((and top-level-prompt
+               (getd top-level-prompt))
+          (funcall top-level-prompt))
+         (t (patom "-> "))))
+
+(defmacro top-read (&rest args)
+   `(cond ((and top-level-read
+               (getd top-level-read))
+          (funcall top-level-read ,@args))
+         (t (read ,@args))))
+
+(defmacro top-eval (&rest args)
+   `(cond ((and top-level-eval
+               (getd top-level-eval))
+          (funcall top-level-eval ,@args))
+         (t (eval ,@args))))
+
+(defmacro top-print (&rest args)
+   `(cond ((and top-level-print
+               (getd top-level-print))
+          (funcall top-level-print ,@args))
+         (t (print ,@args))))
+
+;------------------------------------------------------
+;  Top level function for franz                        jkf, march 1980
+;
+; The following function contains the top-level read, eval, print 
+; loop.  With the help of the error handling functions, 
+; break-err-handler and  debug-err-handler,  franz-top-level provides
+; a reasonable enviroment for working with franz lisp.  
+; 
+
+(def franz-top-level
+  (lambda nil
+     (putd 'reset (getd 'franz-reset))
+     (username-to-dir-flush-cache)      ; clear tilde expansion knowledge
+      (cond ((or (not (boundp 'franz-not-virgin))
+                (null franz-not-virgin))
+            (setq franz-not-virgin t
+                  + nil ++ nil +++ nil
+                  * nil ** nil *** nil)
+            (setq ER%tpl 'break-err-handler)
+            (top-init)))
+     
+     ; loop forever
+     (do ((+*) (-) (retval))
+        (nil)
+        (setq retval
+         (*catch 
+         '(top-level-catch break-catch)
+          ; begin or return to top level
+          (progn
+             (setq debug-level-count 0   break-level-count 0
+                  evalhook nil   funcallhook nil)
+             (cond (tpl-errlist (mapc 'eval tpl-errlist)))
+            (do ((^w nil nil))
+                (nil)
+                (cond (user-top-level (funcall user-top-level))
+                      (t (top-prompt)
+                         (cond ((eq top-level-eof
+                                    (setq - 
+                                          (car (errset (top-read nil 
+                                                             top-level-eof)))))
+                                (cond ((not (status isatty))
+                                       (exit)))
+                                (cond ((null (status ignoreeof))
+                                       (terpr)
+                                       (print 'Goodbye)
+                                       (terpr)
+                                       (exit))
+                                      (t (terpr)
+                                         (setq - ''EOF)))))
+                         (setq +* (top-eval -))
+                         ; update list of old forms
+                         (let ((val -))
+                              (let ((o+ +) (o++ ++))
+                                   (setq +   val
+                                         ++  o+
+                                         +++ o++)))
+                         ; update list of old values
+                         (let ((val +*))
+                              (let ((o* *) (o** **))
+                                   (setq *   val
+                                         **  o*
+                                         *** o**)))
+                         (top-print +*)
+                         (terpr)))))))
+        (terpr)
+        (patom "[Return to top level]")
+        (terpr)
+        (cond ((eq 'reset retval) (old-reset-function))))))
+
+
+
+
+\f
+; debug-err-handler is the clb of ER%all when we are doing debugging
+; and we want to catch all errors.
+; It is just a read eval print loop with errset.
+; the only way to leave is: 
+;   (reset) just back to top level
+;   (return x) return the value to the error checker. 
+;              if nil is returned then we will continue as if the error
+;              didn't occur. Otherwise if the returned value is a list,
+;              then if the error is continuable, the car of that list
+;              will be returned to recontinue computation.
+;   ^D continue as if this handler wasn't called.
+; the form of errmsgs is:
+;  (error_type unique_id continuable message_string other_args ...)
+;
+(def debug-err-handler
+   (lexpr (n)
+         ((lambda (message debug-level-count retval ^w piport)
+             (cond ((greaterp n 0)
+                    (print 'Error:)
+                    (mapc '(lambda (a) (patom " ") (patom a) )
+                          (cdddr (arg 1)))
+                    (terpr)))
+             (setq ER%all 'debug-err-handler)
+             (do ((retval)) (nil)
+                 (cond ((dtpr
+                           (setq retval
+                                 (errset
+                                    (do ((form)) (nil)
+                                        (patom "D<")
+                                        (patom debug-level-count)
+                                        (patom ">: ")
+                                        (cond ((eq top-level-eof
+                                                   (setq form
+                                                         (top-read nil
+                                                               top-level-eof)))
+                                               (cond ((null (status isatty))
+                                                      (exit)))
+                                               (return nil))
+                                              ((and (dtpr form)
+                                                    (eq 'return
+                                                        (car form)))
+                                               (return (eval (cadr form))))
+                                              (t (setq form (top-eval form))
+                                                 (top-print form)
+                                                 (terpr)))))))
+                        (return (car retval))))))
+          nil
+          (add1 debug-level-count)
+          nil
+          nil
+          nil)))
+\f
+; this is the break handler, it should be tied to 
+; ER%tpl always.
+; it is entered if there is an error which no one wants to handle.
+; We loop forever, printing out our error level until someone
+; types a ^D which goes to the next break level above us (or the 
+; top-level if there are no break levels above us.
+; a (return n) will return that value to the error message
+; which called us, if that is possible (that is if the error is
+; continuable)
+;
+(def break-err-handler
+   (lexpr (n)
+     ((lambda (message break-level-count retval rettype ^w piport)
+        (cond ((greaterp n 0)
+               (print 'Error:)
+               (mapc '(lambda (a) (patom " ") (patom a) )
+                     (cdddr (arg 1)))
+               (terpr)
+               (cond ((caddr (arg 1)) (setq rettype 'contuab))
+                     (t (setq rettype nil))))
+              (t (setq rettype 'localcall)))
+
+        (do nil (nil)
+            (cond ((dtpr
+                      (setq retval
+                            (*catch 'break-catch
+                                (do ((form)) (nil)
+                                    (patom "<")
+                                    (patom break-level-count)
+                                    (patom ">: ")
+                                    (cond ((eq top-level-eof
+                                               (setq form
+                                                     (top-read
+                                                        nil
+                                                        top-level-eof)))
+                                           (cond ((null (status isatty))
+                                                  (exit)))
+                                           (eval 1)    ; force interrupt check
+                                           (return (sub1 break-level-count)))
+                                          ((and (dtpr form)
+                                                (eq 'return (car form)))
+                                           (cond ((or (eq rettype 'contuab)
+                                                      (eq rettype 'localcall))
+                                                  (return (ncons (top-eval (cadr form)))))
+                                                 (t (patom "Can't continue from this error")
+                                                    (terpr))))
+                                          ((and (dtpr form) (eq 'retbrk (car form)))
+                                           (cond ((numberp (setq form (top-eval (cadr form))))
+                                                  (return form))
+                                                 (t (return (sub1 break-level-count)))))
+                                          (t (setq form (top-eval form))
+                                             (top-print form)
+                                             (terpr)))))))
+                   (return (cond ((eq rettype 'localcall)
+                                  (car retval))
+                                 (t retval))))
+                  ((lessp retval break-level-count)
+                   (setq tpl-errlist errlist)
+                   (*throw 'break-catch retval))
+                  (t (terpr)))))
+      nil
+      (add1 break-level-count)
+      nil
+      nil
+      nil
+      nil)))
+\f
+(defvar debug-error-handler 'debug-err-handler) ; name of function to get
+                                               ; control on ER%all error
+(def debugging 
+  (lambda (val)
+         (cond (val (setq ER%all debug-error-handler)
+                    (sstatus translink nil)
+                    (*rset t))
+               (t (setq ER%all nil)))))
+
+
+; the problem with this definition for break is that we are
+; forced to put an errset around the break-err-handler. This means
+; that we will never get break errors, since all errors will be
+; caught by our errset (better ours than one higher up though).
+; perhaps the solution is to automatically turn debugmode on.
+;
+(defmacro break (message &optional (pred t))
+  `(*break ,pred ',message))
+
+(def *break
+  (lambda (pred message)
+     (let ((^w nil))
+         (cond ((not (boundp 'break-level-count)) (setq break-level-count 1)))
+         (cond (pred (terpr)
+                     (patom "Break ")
+                     (patom message)
+                     (terpr)
+                     (do ((form))
+                         (nil)
+                         (cond ((dtpr (setq form (errset (break-err-handler))))
+                                (return (car form))))))))))
+
+
+; this reset function is designed to work with the franz-top-level.
+; When franz-top-level begins, it makes franz-reset be reset. 
+; when a reset occurs now, we set the global variable tpl-errlist to 
+; the current value of errlist and throw to top level.  At top level,
+; then tpl-errlist will be evaluated.
+;
+(def franz-reset
+  (lambda nil
+         (setq tpl-errlist errlist)
+         (errset (*throw 'top-level-catch 'reset)
+                 nil)
+         (old-reset-function)))
+
+
+(declare (special $ldprint))
+
+;--- read-in-lisprc-file
+; search for a lisp init file.  Look first in . then in $HOME
+; look first for .o , then .l and then "",
+; look for file bodies .lisprc and then lisprc
+; 
+(def read-in-lisprc-file
+   (lambda nil
+      (setq break-level-count 0        ; do this in case break
+           debug-level-count 0)   ; occurs during readin
+      (*catch '(break-catch top-level-catch)
+             (do ((dirs `("." ,(getenv 'HOME)) (cdr dirs))
+                  ($ldprint nil $ldprint))     ; prevent messages
+                 ((null dirs))
+                 (cond ((do ((name '(".lisprc" "lisprc") (cdr name)))
+                            ((null name))
+                            (cond ((do ((ext '(".o" ".l" "") (cdr ext))
+                                        (file))
+                                       ((null ext))
+                                       (cond ((probef
+                                                 (setq file
+                                                       (concat (car dirs)
+                                                               "/"
+                                                               (car name)
+                                                               (car ext))))
+                                              (cond ((atom (errset (load file)))
+                                                     (patom
+                                                        "Error loading lisp init file ")
+                                                     (print file)
+                                                     (terpr)
+                                                     (return 'error)))
+                                              (return t))))
+                                   (return t))))
+                        (return t)))))))
+
+(putd 'top-level (getd 'franz-top-level))
+
+; if this is the first time this file has been read in, then 
+; make franz-reset be the reset function, but remember the original
+; reset function as old-reset-function.  We need the old reset function
+; if we are going to allow the user to change top-levels, for in 
+; order to do that we really have to jump all the way up to the top.
+(cond ((null (getd 'old-reset-function))
+       (putd 'old-reset-function (getd 'reset))))
+
+
+;---- autoloader functions
+
+(def undef-func-handler
+  (lambda (args)
+    (prog (funcnam file)
+         (setq funcnam (caddddr args))
+         (cond ((symbolp funcnam) 
+                (cond ((setq file (or (get funcnam 'autoload)
+                                      (get funcnam 'macro-autoload)))
+                       (cond ($ldprint
+                              (patom "[autoload ") (patom file)
+                              (patom "]")(terpr)))
+                       (load file))
+                      (t (return nil)))
+                (cond ((getd funcnam) (return (ncons funcnam)))
+                      (t (patom "Autoload file " ) (print file)
+                         (patom " does not contain function ")
+                         (print funcnam)
+                         (terpr)
+                         (return nil))))))))
+
+(setq ER%undef 'undef-func-handler)
+
+(declare (special $ldprint))
+;--- autorunlisp :: check if this lisp is supposed to run a program right
+; away.
+;
+(defun autorunlisp nil
+  (cond ((and (> (argv -1) 2) (equal (argv 1) '-f))
+        (let ((progname (argv 2))
+              ($ldprint nil)
+              (searchlist nil))        ; don't give fasl messages
+             (setq searchlist (cvtsearchpathtolist (getenv 'PATH)))
+             ; give two args to load to insure that a fasl is done.
+             (cond ((null 
+                     (errset (load-autorunobject progname searchlist)))
+                    (exit 0))
+                   (t t))))))
+
+
+(defun cvtsearchpathtolist (path)
+  (do ((x (explodec path) (cdr x))
+       (names nil)
+       (cur nil))
+      ((null x) 
+       (nreverse names))
+      (cond ((or (eq ': (car x)) 
+                (and (null (cdr x)) (setq cur (cons (car x) cur))))
+            (cond (cur (setq names (cons (implode (nreverse cur))
+                                         names))
+                       (setq cur nil))
+                  (t (setq names (cons '|.| names)))))
+           (t (setq cur (cons (car x) cur))))))
+
+(defun load-autorunobject (name search)
+  (cond ((memq (getchar name 1) '(/ |.|))
+        (cond ((probef name) (fasl name))
+              (t (error "From lisp autorun: can't find file to load"))))
+       (t (do ((xx search (cdr xx))
+               (fullname))
+              ((null xx) (error "Can't find file to execute "))
+              (cond ((probef (setq fullname (concat (car xx) "/" name)))
+                     (return (fasl-a-file fullname nil nil))))))))
+
+;--- command-line-args :: return a list of the command line arguments
+; The list does not include the name of the program being executed (argv 0).
+; It also doesn't include the autorun flag and arg.
+;
+(defun command-line-args ()
+   (do ((res nil (cons (argv i) res))
+       (i (1- (argv -1)) (1- i)))
+       ((<& i 1)
+       (if (and (eq '-f (car res))
+                (cdr res))
+          then (cddr res)
+          else res))))
+
+(defun debug fexpr (args)
+  (load 'fix)  ; load in fix package
+  (eval (cons 'debug args)))   ; enter debug through eval
+
+;-- default autoloader properties
+
+(putprop 'trace (concat lisp-library-directory "/trace") 'autoload)
+(putprop 'untrace (concat lisp-library-directory "/trace") 'autoload)
+
+(putprop 'step (concat lisp-library-directory "/step") 'autoload)
+(putprop 'editf (concat lisp-library-directory "/cmuedit") 'autoload)
+(putprop 'editv (concat lisp-library-directory "/cmuedit") 'autoload)
+(putprop 'editp (concat lisp-library-directory "/cmuedit") 'autoload)
+(putprop 'edite (concat lisp-library-directory "/cmuedit") 'autoload)
+
+(putprop 'defstruct (concat lisp-library-directory "/struct") 'macro-autoload)
+(putprop 'defstruct-expand-ref-macro
+        (concat lisp-library-directory "/struct") 'autoload)
+(putprop 'defstruct-expand-cons-macro
+        (concat lisp-library-directory "/struct") 'autoload)
+(putprop 'defstruct-expand-alter-macro
+         (concat lisp-library-directory "/struct") 'autoload)
+
+(putprop 'loop      (concat lisp-library-directory "/loop")   'macro-autoload)
+(putprop 'defflavor
+        (concat lisp-library-directory "/flavors") 'macro-autoload)
+(putprop 'defflavor1
+        (concat lisp-library-directory "/flavors") 'autoload)
+
+(putprop 'format (concat lisp-library-directory "/format") 'autoload)
+(putprop 'ferror (concat lisp-library-directory "/format") 'autoload)
+
+(putprop 'make-hash-table
+        (concat lisp-library-directory "/hash") 'autoload)
+(putprop 'make-equal-hash-table
+        (concat lisp-library-directory "/hash") 'autoload)
+
+(putprop 'describe (concat lisp-library-directory "/describe") 'autoload)
+
+(putprop 'cgol (concat lisp-library-directory "/cgol/cgoll")   'autoload)
+(putprop 'cgolprint (concat lisp-library-directory "/cgol/cgp")   'autoload)
+
+; probably should be in franz so we don't have to autoload
+(putprop 'displace  (concat lisp-library-directory "/machacks")   'autoload)
diff --git a/usr/src/ucb/lisp/lisplib/tpl.l b/usr/src/ucb/lisp/lisplib/tpl.l
new file mode 100644 (file)
index 0000000..f6ece57
--- /dev/null
@@ -0,0 +1,916 @@
+(setq rcs-tpl-
+   "$Header: tpl.l,v 1.4 83/09/04 10:20:03 jkf Exp $")
+
+;                              -[Sun Sep  4 10:18:42 1983 by jkf]-
+;
+
+; to do
+; ?state : display  status translink, *rset, displace-macros.
+;              current error, prinlevel and prinlength
+;         add a way of modifying the values
+; ?bk [n] : do a baktrace (default 10 frames from bottom)
+; ?zo [n] : add an optional number of frames to zoom
+; ?retf : return value from 'current' frame
+; ?retry : retry expr in 'current' frame (required mod to lisp).
+;
+; the frame re-eval question is not asked when it should.
+; interact with tracebreaks correctly
+;
+; add stepper.
+; get 'debugging' to work ok.
+
+;--- state
+;
+(declare (special tpl-debug-on tpl-step-on
+                 tpl-top-framelist tpl-bot-framelist
+                 tpl-eval-flush tpl-trace-flush
+                 tpl-prinlength tpl-prinlevel
+                 prinlevel prinlength
+                 tpl-commands tpl-break-level
+                 tpl-spec-char
+                 tpl-last-loaded
+                 tpl-level
+                 tpl-fcn-in-eval
+                 tpl-contuab
+                 ER%tpl ER%all given-history res-history
+                 tpl-stack-bad tpl-stack-ok
+                 tpl-history-count
+                 tpl-history-show
+                 tpl-dontshow-tpl
+                 tpl-step-enable       ;; if stepping is on
+                 tpl-step-print        ;; if should print step forms
+                 tpl-step-triggers     ;; list of fcns to enable step
+                 tpl-step-countdown    ;; if positive, then don't break
+                 tpl-step-reclevel     ;; recursion level
+                 evalhook funcallhook
+                 *rset % piport
+                 debug-error-handler
+                 ))
+
+(putd 'tpl-eval (getd 'eval))
+(putd 'tpl-funcall (getd 'funcall))
+(putd 'tpl-evalhook (getd 'evalhook))
+(putd 'tpl-funcallhook (getd 'funcallhook))
+
+
+;--- macros which should be in the system
+;
+(defmacro evalframe-type (evf) `(car ,evf))
+(defmacro evalframe-pdl (evf)  `(cadr ,evf))
+(defmacro evalframe-expr (evf) `(caddr ,evf))
+(defmacro evalframe-bind (evf) `(cadddr ,evf))
+(defmacro evalframe-np (evf)   `(caddddr ,evf))
+(defmacro evalframe-lbot (evf) `(cadddddr ,evf))
+
+
+;; messages are passed between break levels by means of catch and
+;; throw:
+(defmacro tpl-throw (value) `(*throw 'tpl-break-catch ,value))
+(defmacro tpl-catch (form) `(*catch 'tpl-break-catch ,form))
+
+; A tpl-catch is placed around the prompting and evaluation of forms.
+; if something abnormal happens in the evaluation, a tpl-throw is done
+; which then tells the break look that something special should be
+; done.
+;
+; messages:
+;   contbreak  -  this tells the break level to print out the message
+;                it prints when it is entered (such as the error message).
+;                [see poplevel message]. 
+;   poplevel   -  tells the break level to jump up to the next higher
+;                break level and continue there.  It sends  contbreak
+;                message to that break level so that it will remind the
+;                user what the state is. [see cmd: ?pop ]
+;   reset      -  This tells the break level to send a reset to the next
+;                higher break level.  Thus a reset is done by successive
+;                small pops.  This isn't totally necessary, but it is
+;                clean.
+;  (retbreak v) - return from the break level, returning the value v.
+;                If this an error break, then we return (list v) since
+;                that is required to indicate that an error has been
+;                handled.
+;  (retry v)   - instead of asking for a new value, retry the given one.
+;  popretry     - take the expression that caused the current break and
+;                send a (retry expr) message to the break level above us
+;                so that it can be tried again.
+
+(setq tpl-eval-flush nil  tpl-trace-flush nil
+   tpl-prinlevel 3 tpl-prinlength 4
+   tpl-spec-char #/?)
+
+(or (boundp 'tpl-last-loaded) (setq tpl-last-loaded nil))
+
+(defun tpl nil
+   (let ((debug-error-handler 'tpl-err-all-fcn))
+      (setq ER%tpl 'tpl-err-tpl-fcn)
+      (putd '*break (getd 'tpl-*break))
+      (setq given-history nil
+           res-history   nil
+           tpl-debug-on  nil
+           tpl-step-on   nil
+           tpl-top-framelist nil
+           tpl-bot-framelist nil
+           tpl-stack-bad t
+           tpl-stack-ok nil
+           tpl-fcn-in-eval nil
+           tpl-level nil
+           tpl-history-count 0
+           tpl-break-level -1
+           tpl-dontshow-tpl t
+           tpl-history-show 10
+           tpl-step-enable nil
+           tpl-step-countdown 0
+           tpl-step-reclevel 0)
+      (do ((retv))
+         (nil)
+         (setq retv
+               (tpl-catch
+                  (tpl-break-function nil))))))
+
+
+;--- do-one-transaction
+;  do a single read-eval-print transaction
+;  If eof-form is given, then we provide a prompt and read the input,
+;   otherwise given is what we use, but we print the prompt and the
+;   given input before evaling it again.
+; (given must be in the form (sys|user ..)
+;
+(defun do-one-transaction (given prompt eof-form)
+   (let (retv)
+      (patom prompt)
+      (If eof-form
+        then (setq given
+                   (car (errset (ntpl-read nil eof-form))))
+             (If (eq eof-form given)
+                then (If (status isatty)
+                        then (msg "EOF" N)
+                             (setq given '(sys  <eof>))
+                        else (exit)))
+        else (tpl-history-form-print given)
+             (terpr))
+      (add-to-given-history given)
+      (If (eq 'user (car given))
+        then (setq tpl-stack-bad t)
+             (setq retv
+                   (if tpl-step-enable
+                      then (tpl-evalhook (cdr given)
+                                         'tpl-do-evalhook
+                                         'tpl-do-funcallhook)
+                      else (tpl-eval (cdr given))))
+             (setq tpl-stack-bad t)
+        else (setq retv (process-fcn (cdr given)))
+             (setq tpl-stack-bad (not tpl-stack-ok)))
+      (add-to-res-history retv)
+      (ntpl-print retv)
+      (terpr)
+      ))
+                    
+
+;; reader
+; if sees a rpar as the first non space char, it just reads all chars
+; return (sys . form)  where form is a list, e.g
+;                      )foo bar baz rets (sys foo bar baz)
+;  or
+;  (user . form)
+; note: if nothing is typed, (sys) is returned
+;
+(defun ntpl-read (port eof-form)
+   (let (ch)
+      ; skip all spaces
+      (do ()
+         ((and (not (eq (setq ch (tyipeek port)) #\space))
+               (not (eq ch #\newline))))
+         (setq ch (tyi)))
+      (If (eq ch #\eof)
+        then eof-form
+        else (setq ch (tyi port))
+             (If (eq ch tpl-spec-char)
+                then (do ((xx (list #\lpar) (cons (tyi) xx)))
+                         ((or (eq #\eof (car xx))
+                              (eq #\newline  (car xx)))
+                          (cons 'sys
+                                (car (errset
+                                        (readlist
+                                           (nreverse
+                                              (cons #\rpar (cdr xx)))))))))
+                else (untyi ch)
+                     (cons 'user (read port eof-form))))))
+
+;--- tpl-history-form-print :: the inverse of tpl-read
+; this takes the history form of an expression and prints it out
+; just as the user would have typed it.
+;
+(defun tpl-history-form-print (form)
+   (If (eq 'user (car form))
+      then (print (cdr form))
+      else (patom "?")
+          (mapc '(lambda (x) (print x) (patom " ")) (cdr form))))
+
+(defun ntpl-print (form)
+   (print form))
+
+(setq tpl-commands
+   '( ((help h) tpl-command-help
+       " [cmd] - print general or specific info "
+       " '?help' - print a short description of all commands "
+       " '?help cmd' - print extended information on the given command ")
+      ( ? tpl-command-redo
+       " [args] - redo last or previous command "
+       " '??' - redo last user command "
+       " '?? n' - (for n>0) redo command #n (as printed by ?history)"
+       " '?? -n' - (for n>0) redo n'th previous command (?? -1 == ??)"
+       " '?? symb' - redo last with car == symb"
+       " '?? symb *' - redo last with car == symb*")
+      ( (his history) tpl-command-history
+       " [r] - print history list "
+       " ?history, ?his - print list of commands previously executed"
+       " '?his r' - print results too")
+      ( (re reset) tpl-command-reset
+       " - pop up to the top level"
+       " '?re, ?reset', pop up to the top level ")
+      ( tr tpl-command-trace
+       " [fn ..] - trace"
+       " '?tr' - print list of traced functions"
+       " '?tr fn ...' - trace given functions, can be fn or (fn cmd ...)"
+       "       where cmds are trace commands")
+      ( step tpl-command-step
+       " [t] [funa funb ...] step always or when specific function hit"
+       " '?step t' - step starting right away "
+       " '?step funa funb' - step when either funa or funb to be called ")
+      ( soff tpl-command-stepoff
+       " - turn off stepping "
+       " '?soff' - turn off stepping ")
+      ( sc tpl-command-sc
+       " [n] - continue stepping [don't break for n steps] "
+       " '?sc' -  do one step then break "
+       " '?sc n' - step for n steps before breaking "
+       "           if n is a non integer (e.g. inf) then "
+       "           step forever without breaking ")
+      ( state tpl-command-state
+       " [vals] - print or change state "
+       " 'state' - print current state in short form "
+       " 'state l' - print state in long form"
+       " 'state sym val ... ...' - set values of state "
+       "       symbols are those given in 'state  l' list")
+      ( prt tpl-command-prt
+       " - pop up a level and retry the command which caused this break"
+       " ?prt - do a ?pop followed by a retry of the command which"
+       "       caused this break to be entered")
+      ( ld  tpl-command-load
+       " [file ...] - load given or last files"
+       " 'ld'  - loads the last files loaded with ?ld"
+       " 'ld file ...' - loads the given files")
+      ( debug tpl-command-debug
+       " [off] - toggle debug state "
+       " 'debug' Turns on debugging.  When debug is on then"
+       "       enough information is kept around for viewing"
+       "       and quering evaluation stack"
+       " 'debug off' - Turns off debuging" )
+      ( pop tpl-command-pop
+       " - pop up to previous break level"
+       " 'pop' - if not at top level, pop up to the break level"
+       "       above this one")
+      ( ret tpl-command-ret
+       " [val] - return value from this break loop "
+       " 'ret [val]' if this is a break look due to a break command "
+       "       or a continuable error, evaluate val (default nil)"
+       "       and return it to the function that found an error,"
+       "       allowing it to continue")
+      
+      ( zo tpl-command-zoom
+       " - view a portion of evaluation stack"
+       " 'zo' - show a portion above and below the 'current' stack"
+       "       frame.  Use )up and )dn or alter current stack frame")
+      ( dn tpl-command-down
+       " [n] - go down stack frames "
+       " 'dn' - move the current stack frame down one.  Down refers to"
+       "       older stack frames"
+       " 'dn n' - n is a fixnum telling how many stack frames to go down"
+       " 'dn n z' - after going down, do a zoom"
+       " After dn is done, a limited zoom will be done")
+      ( up tpl-command-up
+       " [n] - go up stack frames "
+       " 'up' - move the current stack frame up one.  Up refers to"
+       "       younger stack frames"
+       " 'up n' - n is a fixnum telling how many stack frames to go up")
+      ( ev tpl-command-ev
+       " symbol - eval the given symbol wrt the current frame "
+       " 'ev symbol' - determine the value of the given symbol"
+       "       after restoring the bindings to the way they were"
+       "       when the current frame was current.  see ?zo,?up,?dn")
+      ( pp tpl-command-pp
+       " - pretty print the current frame "
+       " 'pp' - pretty print the current frame (see ?zo, ?up, ?dn)")
+      ( <eof> tpl-command-pop
+       " - pop one break level up "
+       " '^D' - if connect to tty, pops up one break level,"
+       "        otherwise, exits doesn't exit unless  "))
+   )
+              
+;--- process-fcn :: do a user command
+;
+(defun process-fcn (form)
+   (let ((sel (car form)))
+      (setq tpl-stack-ok nil)
+      (do ((xx tpl-commands (cdr xx))
+          (this))
+         ((null xx)
+          (msg "Illegal command, type ?help for list of commands" N))
+         (If (or (and (symbolp (setq this (caar xx)))
+                      (eq sel this))
+                 (and (dtpr this)
+                      (memq sel this)))
+             then (return (tpl-funcall (cadar xx) form))))))
+                           
+             
+   
+;--- tpl commands
+;
+
+;--- tpl-command-help
+(defun tpl-command-help (x)
+   (setq tpl-stack-ok t)
+   (If (cdr x)
+      then (do ((xx tpl-commands (cdr xx))
+               (sel (cadr x))
+               (this))
+              ((null xx)
+               (msg "I don't know that command" N))
+              ; look for command in tpl-commands list
+              (If (or (and (symbolp (setq this (caar xx)))
+                      (eq sel this))
+                 (and (dtpr this)
+                      (memq sel this)))
+                 then (return (do ((yy (cdddar xx) (cdr yy)))
+                                  ((null yy))
+                                  ; print all extended documentation
+                                  (patom (car yy))
+                                  (terpr)))))
+      else ; print short info on all commands
+          (mapc #'(lambda (x)
+                     (let ((sel (car x)))
+                        ; first print selector or selectors
+                        (If (dtpr sel)
+                           then (patom (car sel))
+                                (mapc #'(lambda (y) (patom ",") (patom y))
+                                       (cdr sel))
+                           else (patom sel))
+                        ; next print documentation
+                        (patom (caddr x))
+                        (terpr)))
+                 tpl-commands))
+   nil)
+
+(defun tpl-command-load (args)
+   (setq args (cdr args))
+   (If args
+      then (setq tpl-last-loaded args)
+          (mapc 'load args)
+    elseif tpl-last-loaded
+      then (mapc 'load tpl-last-loaded)
+      else (msg "Nothing to load" N)))
+
+             
+(defun tpl-command-trace (args)
+   (setq args (cdr args))
+   (apply 'trace args))
+
+        
+   
+;--- tpl-command-state
+;
+(defun tpl-command-state (x)
+   (msg " State:  debug " tpl-debug-on ", step " tpl-step-enable N))
+
+;--- tpl-command-debug
+;
+(defun tpl-command-debug (x)
+   (If (memq 'off (cdr x))
+      then (*rset nil)
+          (msg "Debug is off" N)
+          (setq tpl-debug-on nil)
+      else (*rset t)
+          (sstatus translink nil)
+          (msg "Debug is on" N)
+          (setq tpl-debug-on t)))
+
+;--- tpl-command-zoom
+;
+(defun tpl-command-zoom (x)
+   (tpl-update-stack)
+   (setq tpl-stack-ok t)
+   (tpl-zoom))
+
+(defun tpl-command-down (args)
+   ;; go down the evaluation stack and zoom
+   ;; down means towards older frames
+   (setq tpl-stack-ok t)
+   (let ((count 1))
+      (If (and (fixp (cadr args)) (> (cadr args) 0))
+        then (setq count (cadr args)))
+      (do ((xx count (1- xx)))
+         ((= 0 xx))
+         (If tpl-bot-framelist
+            then (setq tpl-top-framelist (cons (car tpl-bot-framelist)
+                                               tpl-top-framelist)
+                       tpl-bot-framelist (cdr tpl-bot-framelist))))
+      (tpl-command-zoom nil)))
+
+(defun tpl-command-up (args)
+   ;; go up the stack and zoom
+   ;; up is towards more recent stuff
+   ;;
+   (setq tpl-stack-ok t)
+   (let ((count 1))
+      (If (and (fixp (cadr args)) (> (cadr args) 0))
+        then (setq count (cadr args)))
+      (do ((xx count (1- xx)))
+         ((= 0 xx))
+         (If tpl-top-framelist
+            then (setq tpl-bot-framelist (cons (car tpl-top-framelist)
+                                               tpl-bot-framelist)
+                       tpl-top-framelist (cdr tpl-top-framelist))))
+      (tpl-command-zoom nil)))
+
+(defun tpl-command-ev (args)
+   ;; ?ev foo
+   ;; determine the value of variable foo with respect to the current
+   ;; evaluation frame.
+   ;;
+   (let ((sym (cadr args)))
+      (If (not (symbolp sym))
+        then (msg "ev must be given a symbol" N)
+       elseif (null tpl-bot-framelist)
+        then (msg "there is no evaluation stack, is debug on?")
+        else (prog1 (car
+                       (errset
+                          (eval sym
+                                (evalframe-bind (car tpl-bot-framelist)))))
+                    (setq tpl-stack-ok t)))))
+
+
+(defun tpl-command-pp (args)
+   (pp-form (evalframe-expr (car tpl-bot-framelist)))
+   (terpr)
+   nil)
+
+;;-- history list maintainers
+;
+; history lists are just lists of forms
+; one for the given, and one for the returned
+;
+(defun most-recent-given () (car given-history))
+
+(defun add-to-given-history (form)
+   (setq given-history (cons form given-history))
+   (setq res-history   (cons nil  res-history))
+   (If (not (eq (car form) 'history))
+       then (setq tpl-history-count (1+ tpl-history-count))))
+
+(defun add-to-res-history (form)
+   (setq res-history (cons form (cdr res-history)))
+   (setq % form))
+
+   
+;--- evalframe generation
+;
+
+(defun tpl-update-stack nil
+   (If tpl-stack-bad
+      then (If (tpl-yorn "Should I re-calc the stack(y/n):")
+             then (tpl-gentrace)
+             else (msg "[not re-calc'ed]" N)
+                  (setq tpl-stack-bad nil))))
+
+;--- tpl-gentrace
+; this is called before an function which references the
+; frame list.  it needn't be called unless one knows that
+; the frame status has changed
+;
+(defun tpl-gentrace ()
+   (let ((templist (tpl-getframelist)))
+      ; templist contains the frame from bottom (oldest) to top
+
+      (setq templist (nreverse templist)) ; now youngest to oldest
+
+      
+      ; determine a new framelist and put it on the bottom list
+      ; the top list is empty.  the first thing in the
+      ; bottom framelist is the 'current' frame.
+
+      ; go though frames, based on flags, flush trace calls
+      ; or eval calls
+      (do ((xx templist (cdr xx))
+          (remember (If tpl-dontshow-tpl then nil else t))
+          (forget-this nil nil)
+          (res)
+          (exp)
+          (flushpoint))
+         ((null xx) (setq tpl-bot-framelist (nreverse res)))
+         (setq exp (evalframe-expr (car xx)))
+         (If (dtpr exp)
+            then (If (and tpl-dontshow-tpl
+                          (memq (car exp) '(tpl-eval tpl-funcall
+                                                     tpl-evalhook
+                                                     tpl-funcallhook)))
+                    then (setq remember nil)))
+         (If (dtpr exp)
+            then (If (and tpl-dontshow-tpl (memq (car exp)
+                                                '(tpl-err-tpl-fcn
+                                                    tpl-funcall-evalhook
+                                                    tpl-do-funcallhook)))
+                     then (setq forget-this t)))
+         (If (and remember (not forget-this))
+             then (setq res (cons (car xx) res)))
+         (If (dtpr exp)
+            then (If (and tpl-dontshow-tpl
+                          (eq (car exp) 'tpl-break-function))
+                    then (setq remember t))))
+
+      (setq tpl-top-framelist nil)))
+
+(defun tpl-getframelist nil
+   (let ((frames)
+        temp)
+      (If *rset
+        then ; Getting the first few frames is tricky because
+             ; the frames disappear quickly.
+             (setq temp (evalframe nil))       ; call to setq
+             (setq temp (evalframe (evalframe-pdl temp)))
+             (do ((xx (list (evalframe (evalframe-pdl temp)))
+                      (cons (evalframe (evalframe-pdl (car xx))) xx)))
+                 ((null (car xx))
+                  (cdr xx))))))
+
+              
+(defun tpl-printframelist (printdown  vals count)
+   (If (null vals)
+      then (If printdown
+             then (msg "*** bottom ***" N)
+             else (msg "*** top ***" N))
+    elseif (= 0 count)
+      then (msg "... " (length vals) " more ..." N)
+    else (If (not printdown)
+           then (tpl-printframelist printdown (cdr vals) (1- count)))
+        (let ((prinlevel tpl-prinlevel)
+              (prinlength tpl-prinlength))
+           ; tag apply type forms with 'a:'
+           (if (eq 'apply (evalframe-type (car vals)))
+              then (msg "a:"))
+           (print (evalframe-expr (car vals)))
+           (terpr))
+        (If printdown
+           then (tpl-printframelist printdown (cdr vals) (1- count)))))
+
+
+(defun tpl-zoom nil
+   (tpl-printframelist nil tpl-top-framelist 4)
+   (msg "// current \\\\" N)
+   (tpl-printframelist t   tpl-bot-framelist 4))
+
+                 
+
+(defmacro errdesc-class (err) `(car ,err))
+(defmacro errdesc-id    (err) `(cadr ,err))
+(defmacro errdesc-contp (err) `(caddr ,err))
+(defmacro errdesc-descr (err) `(cdddr ,err))
+
+;--- error handler
+;
+
+(defun tpl-break-function (reason)
+   (do ((tpl-fcn-in-eval (most-recent-given))
+       (tpl-level reason)
+       (tpl-continuab)
+       (tpl-break-level (1+ tpl-break-level))
+       ;(tpl-step-enable)
+       (prompt)
+       (do-retry nil nil)
+       (retry-value)
+       (retv 'contbreak)
+       (piport nil)
+       (eof-form (ncons nil)))
+       (nil)
+       (If (eq retv 'contbreak)
+         then
+              (If (memq (car reason) '(error derror))
+                 then (if (eq (car reason) 'error)
+                         then (msg "Error: ")
+                         else (msg "DError: "))
+                      (patom (car (errdesc-descr (cdr reason))))
+                      (mapc #'(lambda (x) (patom " ") (print x))
+                             (cdr (errdesc-descr (cdr reason))))
+                      (terpr)
+                      (msg "Form: " (cdr tpl-fcn-in-eval))
+               elseif (eq 'break (car reason))
+                 then (msg "Break: ")
+                      (patom (cadr reason))
+                      (mapc #'(lambda (x) (patom " ") (print x))
+                             (cddr reason)))
+              (terpr)
+              (setq tpl-contuab (or (memq (car reason) '(break derror step))
+                                    (errdesc-contp (cdr reason))))
+              (setq prompt (If reason
+                              then (concat (if (eq (car reason) 'derror)
+                                              then "d"
+                                            elseif (eq (car reason) 'step)
+                                              then "s"
+                                              else "")
+                                           (If tpl-contuab then "c" else "")
+                                           "{"
+                                           tpl-break-level
+                                           "} ")
+                              else "=> "))
+       elseif (eq retv 'reset)
+         then (tpl-throw 'reset)
+       elseif (eq retv 'poplevel)
+         then (tpl-throw 'contbreak)
+       elseif (eq retv 'popretry)
+         then (tpl-throw `(retry ,tpl-fcn-in-eval))
+       elseif (dtpr retv)
+         then (If (eq 'retbreak (car retv))
+                 then (If (eq 'error (car reason))
+                         then (return (cdr retv))      ; return from error
+                         else (return (cadr retv)))
+                 else (If (eq 'retry (car retv))
+                         then (setq do-retry t
+                                    retry-value (cadr retv)))))
+       (setq retv
+            (tpl-catch
+                    (do ()
+                        (nil)
+                        (If (null do-retry)
+                           then (do-one-transaction nil prompt eof-form)
+                           else (do-one-transaction retry-value prompt nil))
+                        (setq do-retry nil)
+                        nil)))))
+
+;--- tpl-err-tpl-fcn
+; attached to ER%tpl, the error will return to top level
+; generic error handler
+;
+(defun tpl-err-tpl-fcn (err)
+   (tpl-break-function (cons 'error err)))
+
+;--- tpl-err-all-fcn
+; attached to ER%all if (debugging t) is done.
+;
+(defun tpl-err-all-fcn (err)
+   (setq ER%all 'tpl-err-all-fcn)
+   (tpl-break-function (cons 'derror err)))
+   
+;-- tpl-command-pop
+; pop a break level
+; 
+(defun tpl-command-pop (x)
+   (If (= 0 tpl-break-level)
+      then (msg "Already at top level " N)
+      else (tpl-throw 'poplevel)))
+
+       
+          
+(defun tpl-command-ret (x)
+   (If tpl-contuab
+      then (tpl-throw (list 'retbreak (eval (cadr x))))
+      else (msg "Can't return at this point" N)))
+
+;--- tpl-command-redo
+; see documentatio above for a list of the various things this accepts
+;
+(defun tpl-command-redo (x)
+   (setq x (cdr x))
+   (If (null x)
+      then (tpl-redo-by-count 1)
+    elseif (fixp (car x))
+      then (If (< (car x) 0)
+             then (tpl-redo-by-count (- (car x)))
+             else (If (not (< (car x) tpl-history-count))
+                     then (msg "There aren't that many commands " N)
+                     else (tpl-redo-by-count (- tpl-history-count (car x)))))
+      else (tpl-redo-by-car x)))
+
+
+;--- tpl-redo-by-car :: locate command to do by the car of the command
+;
+(defun tpl-redo-by-car (x)
+   (let ((command (car x))
+        (substringp (If (eq (cadr x) '*) thenret)))
+      (If substringp
+        then (If (not (symbolp command))
+                then (msg "must give a symbol before *" N)
+                else (let* ((string (get_pname command))
+                            (len (pntlen string)))
+                        (do ((xx (tpl-next-user-in-history given-history)
+                                 (tpl-next-user-in-history (cdr xx)))
+                             (pos))
+                            ((null xx)
+                             (msg "Can't find a match" N))
+                            (If (and (dtpr (cdar xx))
+                                     (symbolp (setq pos (cadar xx))))
+                               then (If (equal (substring pos 1 len)
+                                               string)
+                                       then (tpl-throw
+                                                    `(retry ,(car xx))))))))
+        else (do ((xx (tpl-next-user-in-history given-history)
+                      (tpl-next-user-in-history (cdr xx)))
+                  (pos))
+                 ((null xx)
+                  (msg "Can't find a match" N))
+                 (If (and (dtpr (cdar xx))
+                          (symbolp (setq pos (cadar xx))))
+                    then (If (eq pos command)
+                            then (tpl-throw
+                                         `(retry ,(car xx)))))))))
+                            
+;--- tpl-redo-by-count :: redo n'th previous input
+; n>=0.  if n=0, then redo last.
+;
+(defun tpl-redo-by-count (n)
+   (do ((xx  n (1- xx))
+       (list (tpl-next-user-in-history given-history)
+             (tpl-next-user-in-history (cdr list))))
+       ((or (not (> xx 0)) (null list))
+       (If (null list)
+          then (msg "There aren't that many commands " N)
+          else (tpl-throw `(retry ,(car list)))))))
+
+
+'(defun tpl-next-user-in-history (hlist)
+   (do ((histlist hlist (cdr histlist)))
+       ((or (null histlist)
+           (eq 'user (caar histlist)))
+       histlist)))
+
+(defun tpl-next-user-in-history (hlist)
+   hlist)
+
+;--- tpl-command-prt
+; pop and retry command which failed this time
+;
+(defun tpl-command-prt (x)
+   (tpl-throw 'popretry))
+
+
+;--- tpl-command-history
+;
+(defun tpl-command-history (x)
+   (let (show-res)
+      (If (memq 'r (cdr x))
+        then (setq show-res t))
+      (tpl-command-his-rec tpl-history-show tpl-history-count show-res
+                          given-history res-history)))
+
+(defun tpl-command-his-rec (count current show-res hlist rhlist)
+   (If (and hlist (> count 0))
+      then (tpl-command-his-rec (1- count) (1- current) show-res
+                               (cdr hlist) (cdr rhlist)))
+   (If hlist
+      then
+          (let ((prinlevel tpl-prinlevel)
+                (prinlength tpl-prinlength))
+             (msg current ": ") (tpl-history-form-print (car hlist))
+             (terpr)
+             (If show-res
+                then (msg "% " current ": " (car rhlist) N)))))
+
+
+(defun tpl-command-reset (x)
+   (tpl-throw 'reset))
+
+(defun tpl-yorn (message)
+   (drain piport)
+   (msg message)
+   (let ((ch (tyi)))
+      (drain piport)
+      (eq #/y ch)))
+
+       
+;--- tpl-*break :: handle breaks
+;  when tpl starts, this is put on *break's function cell
+;
+(defun tpl-*break (pred message)
+   (let ((^w nil))
+      (cond (pred (tpl-break-function (list 'break message))))))
+
+
+
+;; stepping code
+(defun tpl-command-step (args)
+   (setq tpl-step-enable t
+        tpl-step-print nil
+        tpl-step-triggers nil
+        tpl-step-countdown 0)
+   (if (memq t args)
+      then (setq tpl-step-print t)
+      else (setq tpl-step-triggers args))
+   (*rset t)
+   (setq evalhook nil funcallhook nil)
+   (sstatus translink nil)
+   (sstatus evalhook t))
+
+
+(defun tpl-command-stepoff (args)
+   ;; we don't turn off status evalhook because then an
+   ;; evalhook would cause an error (this probably should be fixed)
+   (sstatus evalhook nil)
+   (setq tpl-step-enable nil
+        tpl-step-print nil))
+
+(defun tpl-command-sc (args)
+   ;; continue after step
+   (if (cdr args)
+      then (if (fixp (cadr args))
+             then (setq tpl-step-countdown (cadr args))
+             else (setq tpl-step-countdown 100000)))
+   (tpl-throw `(retbreak ,tpl-step-enable)))
+
+(defun tpl-do-evalhook (arg)
+   ;; arg is the form to eval
+   (tpl-funcall-evalhook arg 'eval))
+
+(defun tpl-do-funcallhook (&rest args)
+   ;; this is called with n args.
+   ;; args 0 to n-2 are the actual arguments.
+   ;; arg n-1 is the function to call (notice that it comes at the end)
+   ; the list in 'args' is a fresh list, we can clobber it
+   (let (name)
+      ; strip the last cons cells from the args list
+      ; there will be at least one element in the list,
+      ; namely the function being called
+      (if (cdr args)
+        then ; case of at least one argument
+             (do ((xx args (cdr xx)))
+                 ((null (cddr xx))
+                  (setq name (cadr xx))
+                  (setf (cdr xx) nil)))
+        else ; case of zero arguments
+             (setq name (car args) args nil))
+      
+      (tpl-funcall-evalhook (cons name args) 'funcall)))
+
+
+(defun tpl-funcall-evalhook (fform type)
+   ;; function called after an evalhook or funclalhook is triggered
+   ;; The form is an s-expression to be evaluated
+   ;; The type is either 'eval' or 'funcall',
+   ;;   eval meaning that the form is something to be eval'ed
+   ;;   funcall meaning that the car of the form is the function to
+   ;;   be applied to the list which is the cdr [actually the cdr
+   ;;   is spread out on the stack and a 'funcall' is done, but this
+   ;;   is what apply does anyway.
+   ;; Upon entry we optionally print, optionally break, optionally continue
+   ;;    stepping, and then optionally print the value
+   ;; We print if tpl-step-print is t
+   ;; We break if tpl-step-print is t and tpl-step-countdown is <= 0
+   ;; We continue stepping if tpl-step-enable is t
+   ;; We print the result if we continued stepping.
+   ;; 
+   ;; note: if it were possible to call evalhook and funcallhook if
+   ;; (status evalhook) were nil, then we could make ?soff turn off
+   ;; (status evalhook), making things run faster [as it is now, stepping
+   ;; continues until we reach top-level again.  We just don't print
+   ;; things out]
+   ;;
+   (let ((tpl-step-reclevel (1+ tpl-step-reclevel)))
+      (if (and (not tpl-step-print)
+              (dtpr fform)
+              (memq (car fform) tpl-step-triggers))
+        then (setq tpl-step-print t))
+      (if tpl-step-print
+        then (tpl-step-printform tpl-step-reclevel type fform)
+             (if (<& tpl-step-countdown 1)
+                then (setq tpl-step-enable (tpl-break-function '(step)))
+                else (setq tpl-step-countdown (1- tpl-step-countdown))))
+      (if tpl-step-enable
+        then (let ((newval))
+                (setq newval (if (eq type 'eval)
+                                then (tpl-evalhook fform
+                                                   'tpl-do-evalhook
+                                                   'tpl-do-funcallhook)
+                                else (tpl-funcallhook fform
+                                                      'tpl-do-funcallhook
+                                                      'tpl-do-evalhook)))
+                (if tpl-step-print
+                   then (tpl-step-printform tpl-step-reclevel 'r newval))
+                newval)
+        else (if (eq type 'eval)
+                then (tpl-evalhook fform nil nil)
+                else (tpl-funcallhook fform nil nil)))))
+      
+
+(defun tpl-step-printform (indent key form)
+   (printblanks indent nil)
+   (let ((prinlevel 4) (prinlength 4))
+      (msg (if (eq key 'r)
+             then '"=="
+           elseif (eq key 'funcall)
+             then 'f:
+           elseif (eq key 'eval)
+             then 'e:
+             else key)
+          form N)))
+
+; in order to use this: (setq user-top-level 'tpl)
+
+          
+(putprop 'tpl t 'version)
diff --git a/usr/src/ucb/lisp/lisplib/trace.l b/usr/src/ucb/lisp/lisplib/trace.l
new file mode 100644 (file)
index 0000000..4e3797a
--- /dev/null
@@ -0,0 +1,517 @@
+(setq rcs-trace-
+   "$Header: /usr/lib/lisp/RCS/trace.l,v 1.2 83/08/15 22:30:36 jkf Exp $")
+
+;---- The Joseph Lister Trace Package, v1
+;         John Foderaro, Sept 1979
+;------------------------------------------------------------------;
+; Copyright (c) 1979 The Regents of the University of California   ;
+;      All rights reserved.                                       ;
+;------------------------------------------------------------------;
+(eval-when (eval)
+  (setq old-read-table-trace readtable)
+  (setq readtable (makereadtable t))
+  (setq old-uctolc-value (status uctolc))
+  (sstatus uctolc nil)         ; turn off case conversion
+  (load 'charmac)
+  (setsyntax '\; 'macro 'zapline)
+  )
+
+
+
+;----
+; trace uses these properties on the property list:
+;    trace-orig-fcn: original occupant of the function cell
+;    trace-trace-fcn: the value trace puts in the  function cell
+;      (used to check if the trace function has be overwritten).
+;    trace-trace-args: the arguments when function was traced.
+;    trace-printargs: function to print argument to function
+;    trace-printres: function to print result of function
+
+(declare (nlambda T-status T-sstatus)
+  (special piport
+          if ifnot evalin evalout 
+          printargs printres evfcn
+          traceenter traceexit
+          prinlevel prinlength
+          $$traced-functions$$         ; all functions being traced
+          $$functions-in-trace$$       ; active functions 
+          $$funcargs-in-trace$$        ; arguments to active functions.
+          $tracemute                   ; if t, then enters and exits
+                                       ; are quiet, but info is still
+                                       ; kept so (tracedump) will work
+          trace-prinlevel              ; default values
+          trace-prinlength
+          trace-printer                ; function trace uses to print
+          ))
+
+
+
+(cond ((null (boundp '$$traced-functions$$)) (setq $$traced-functions$$ nil)))
+(cond ((null (boundp '$$functions-in-trace$$)) (setq $$functions-in-trace$$ nil)))
+(cond ((null (boundp '$$funcargs-in-trace$$)) (setq $$funcargs-in-trace$$ nil)))
+(cond ((null (boundp '$tracemute)) (setq $tracemute nil)))
+(cond ((null (boundp 'trace-prinlevel)) (setq trace-prinlevel 4)))
+(cond ((null (boundp 'trace-prinlength)) (setq trace-prinlength 5)))
+(cond ((null (boundp 'trace-printer)) (setq trace-printer 'Trace-print)))
+
+;----> It is important that the trace package not use traced functions
+;      thus we give the functions the trace package uses different
+;      names and make them equivalent at this time to their 
+;      traceable counterparts.  
+(defun trace-startup-func nil
+  (do ((i '( (add1 T-add1)(append T-append)
+            (and T-and)  (apply T-apply)
+            (cond T-cond) (cons T-cons) (delq T-delq)
+            (def T-def) (do T-do) (drain T-drain)
+            (dtpr T-dtpr)  (eval T-eval)(funcall T-funcall)
+            (get T-get) (getd T-getd)(getdisc T-getdisc)
+            (greaterp T-greaterp)(lessp T-lessp)
+            (mapc T-mapc) (not T-not)(nreverse T-nreverse)
+            (patom T-patom) (print T-print) (prog T-prog)
+            (patom T-patom)(putd T-putd) 
+            (putprop T-putprop)
+            (read T-read)(remprop T-remprop) (reverse T-reverse)
+            (return T-return)
+            (set T-set) (setq T-setq)
+            (status T-status) (sstatus T-sstatus)
+            (sub1 T-sub1) (terpr T-terpr) 
+            (zerop T-zerop))
+         (cdr i)))
+      ((null i))
+      (putd (cadar i) (getd (caar i)))
+      (putprop (cadar i) t 'Untraceable)))
+
+(trace-startup-func)
+
+
+(putprop 'quote t 'Untraceable)                ; this prevents the common error
+                                       ; of (trace 'foo) from causing big
+                                       ; problems.
+
+;--- trace - arg1,arg2, ... names of functions to trace
+;      This is the main user callable trace routine. 
+; work in progress, documentation incomplete since im not sure exactly
+; where this is going. 
+;
+(def trace
+  (nlambda (argl)
+   (prog (if ifnot evalin evalout funnm  typ
+         funcd did break printargs printres evfcn traceenter traceexit
+         traceargs)
+
+    ; turn off transfer table linkages if they are on
+    (cond ((T-status translink) (T-sstatus translink nil)))
+
+    ; process each argument     
+
+    (do ((ll argl (cdr ll))
+        (funnm) 
+        (funcd))
+       ((null ll))
+      (setq funnm (car ll)
+               if t
+               break nil
+               ifnot nil
+               evalin nil
+               evalout nil
+               printargs nil
+               printres nil
+               evfcn nil
+               traceenter 'T-traceenter
+               traceexit  'T-traceexit
+               traceargs  nil)
+
+       ; a list as an argument means that the user is specifying
+       ; conditions on the trace
+      (cond ((not (atom funnm))
+            (cond ((not (atom (setq funnm (car funnm))))
+                   (T-print (car funnm))
+                   (T-patom '" is non an function name")
+                   (go botloop)))
+            ; remember the arguments in case a retrace is requested
+            (setq traceargs (cdar ll))
+            ; scan the arguments
+            (do ((rr (cdar ll) (cdr rr)))
+                ((null rr))
+                (cond ((memq (car rr) '(if ifnot evalin evalout
+                                           printargs printres evfcn
+                                           traceenter traceexit))
+                       (T-set (car rr) (cadr rr))
+                       (setq rr    (cdr rr)))
+                      ((eq (car rr) 'evalinout)
+                       (setq evalin (setq evalout (cadr rr))
+                             rr (cdr rr)))
+                      ((eq (car rr) 'break)
+                       (setq break t))
+                      ((eq (car rr) 'lprint)
+                       (setq printargs 'T-levprint
+                             printres  'T-levprint))
+                      (t (T-patom '"bad request: ")
+                         (T-print (car rr))
+                         (T-terpr)))))
+           (t (setq traceargs nil)  ;no args given
+              ))
+
+           ; if function is untraceable, print error message and skip
+       (cond ((get funnm 'Untraceable)
+             (setq did (cons `(,funnm untraceable) did))
+             (go botloop)))
+
+
+       ; Untrace before tracing
+       (let ((res (funcall 'untrace (list funnm))))
+         (cond (res (setq did (cons `(,funnm untraced) did)))))
+
+       ; store the names of the arg printing routines if they are
+       ; different than print
+
+       (cond (printargs (T-putprop funnm printargs 'trace-printargs)))
+       (cond (printres  (T-putprop funnm printres 'trace-printres)))
+       (T-putprop funnm traceargs 'trace-trace-args)
+
+       ; we must determine the type of function being traced
+       ; in order to create the correct replacement function
+
+       (cond ((setq funcd (T-getd funnm))
+             (cond ((bcdp funcd)               ; machine code
+                    (cond ((or (eq 'lambda (T-getdisc funcd))
+                               (eq 'nlambda (T-getdisc funcd))
+                               (eq 'macro (T-getdisc funcd)))
+                           (setq typ (T-getdisc funcd)))
+                          ((stringp (T-getdisc funcd)) ; foreign func
+                           (setq typ 'lambda))         ; close enough
+                          (t (T-patom '"Unknown type of compiled function")
+                             (T-print funnm)
+                             (setq typ nil))))
+
+                   ((dtpr funcd)               ; lisp coded
+                    (cond ((or (eq 'lambda (car funcd))
+                               (eq 'lexpr (car funcd)))
+                           (setq typ 'lambda))
+                          ((or (eq 'nlambda (car funcd))
+                               (eq 'macro (car funcd)))
+                           (setq typ (car funcd)))
+                          (t (T-patom '"Bad function definition: ")
+                             (T-print funnm)
+                             (setq typ nil))))
+                   ((arrayp funcd)             ; array
+                    (setq typ 'lambda))
+                   (t (T-patom '"Bad function defintion: ")
+                      (T-print funnm)))
+
+             ; now that the arguments have been examined for this
+             ; function, do the tracing stuff.
+             ; First save the old function on the property list
+
+             (T-putprop funnm funcd 'trace-orig-fcn)
+
+             ; now build a replacement
+
+             (cond
+                ((eq typ 'lambda)
+                 (T-eval
+                    `(T-def
+                        ,funnm
+                        (lexpr (T-nargs)
+                               ((lambda (T-arglst T-res T-rslt
+                                                  $$functions-in-trace$$
+                                                  $$funcargs-in-trace$$)
+                                   (T-do ((i T-nargs (T-sub1 i)))
+                                         ((T-zerop i))
+                                         (T-setq T-arglst
+                                                 (T-cons (arg i) T-arglst)))
+                                   (T-setq $$funcargs-in-trace$$
+                                           (T-cons T-arglst
+                                                   $$funcargs-in-trace$$))
+                                   (T-cond ((T-setq T-res
+                                                    (T-and ,if
+                                                            (T-not ,ifnot)))
+                                            (,traceenter ',funnm T-arglst)
+                                            ,@(cond (evalin
+                                                       `((T-patom ,'":in: ")
+                                                         ,evalin
+                                                         (T-terpr))))
+                                            (T-cond (,break
+                                                      (trace-break)))))
+                                   (T-setq T-rslt
+                                           ,(cond
+                                               (evfcn)
+                                               (t `(T-apply
+                                                      ',funcd
+                                                      T-arglst))))
+                                   (T-cond (T-res
+                                              ,@(cond (evalout
+                                                         `((T-patom ,'":out: ")
+                                                           ,evalout
+                                                           (T-terpr))))
+                                              (,traceexit ',funnm T-rslt)))
+                                   T-rslt)
+                                nil nil nil
+                                (T-cons ',funnm $$functions-in-trace$$)
+                                $$funcargs-in-trace$$))))
+                 (T-putprop funnm (T-getd funnm) 'trace-trace-fcn)
+                 (setq did (cons funnm did)
+                       $$traced-functions$$ (cons funnm
+                                                  $$traced-functions$$)))
+
+                ((or (eq typ 'nlambda)
+                     (eq typ 'macro))
+                 (T-eval
+                    `(T-def ,funnm
+                             (,typ (T-arglst)
+                               ((lambda (T-res T-rslt
+                                               $$functions-in-trace$$
+                                               $$funcargs-in-trace$$)
+                                   (T-setq $$funcargs-in-trace$$
+                                           (T-cons
+                                              T-arglst
+                                              $$funcargs-in-trace$$))
+                                   (T-cond ((T-setq
+                                               T-res
+                                               (T-and ,if
+                                                       (not ,ifnot)))
+                                            (,traceenter
+                                              ',funnm
+                                              T-arglst)
+                                            ,evalin
+                                            (T-cond (,break
+                                                      (trace-break)))))
+                                   (T-setq T-rslt
+                                           ,(cond
+                                               (evfcn `(,evfcn
+                                                         ',funcd
+                                                         T-arglst))
+                                               (t `(T-apply ',funcd
+                                                            T-arglst))))
+                                   (T-cond (T-res
+                                              ,evalout
+                                              (,traceexit ',funnm T-rslt)))
+                                   T-rslt)
+                                nil nil
+                                (cons ',funnm $$functions-in-trace$$)
+                                $$funcargs-in-trace$$))))
+                 (T-putprop funnm (T-getd funnm) 'trace-trace-fcn)
+                 (setq did (cons funnm did)
+                       $$traced-functions$$ (cons funnm
+                                                  $$traced-functions$$)))
+
+                (t (T-patom '"No such function as: ")
+                   (T-print funnm)
+                   (T-terpr)))))
+           botloop )
+        ; if given no args, just return the function currently being traced
+        (return (cond ((null argl) $$traced-functions$$)
+                      (t (T-nreverse did)))))))
+
+;--- untrace
+; (untrace foo bar baz)
+;    untraces foo, bar and baz.
+; (untrace)
+;    untraces all functions being traced.
+;
+
+(def untrace
+  (nlambda (argl)
+          (cond ((null argl) (setq argl $$traced-functions$$)))
+
+          (do ((i argl (cdr i))
+               (tmp)
+               (curf)
+               (res))
+              ((null i)  
+               (cond ((null $$traced-functions$$)
+                      (setq $$functions-in-trace$$ nil)
+                      (setq $$funcargs-in-trace$$ nil)))
+               res)
+              (cond ((and (T-getd (setq curf (car i)))
+                          (eq (T-getd (car i))
+                              (get (car i) 'trace-trace-fcn)))
+                     ; we only want to restore the original definition
+                     ; if this function has not been redefined!
+                     ; we test this by checking to be sure that the
+                     ; trace-trace-property is the same as the function
+                     ; definition.
+                     (T-putd curf (get curf 'trace-orig-fcn))
+                     (T-remprop curf 'trace-orig-fcn)
+                     (T-remprop curf 'trace-trace-fcn)
+                     (T-remprop curf 'trace-trace-args)
+                     (T-remprop curf 'entercount)
+                     (setq $$traced-functions$$ 
+                             (T-delq curf $$traced-functions$$))
+                     (setq res (cons curf res)))))))
+
+
+;--- retrace :: trace again all function thought to be traced.
+;
+(def retrace
+   (nlambda (args)
+       (cond ((null args) (setq args $$traced-functions$$)))
+       (mapcan '(lambda (fcn)
+                   (cond ((and (symbolp fcn)
+                               (not (eq (T-getd fcn)
+                                        (get fcn 'trace-trace-fcn))))
+                          
+                          (funcall 'trace
+                                   `((,fcn ,@(get fcn 'trace-trace-args)))))))
+               args)))
+
+;--- tracedump :: dump the currently active trace frames
+;
+(def tracedump
+  (lambda nil
+         (let (($tracemute nil))
+              (T-tracedump-recursive $$functions-in-trace$$ 
+                                     $$funcargs-in-trace$$))))
+
+
+;--- traceargs :: return list of args to currently entered traced functions
+;  call is:
+;      (traceargs foo)  returns first call to foo starting at most current
+;       (traceargs foo 3) returns args to third call to foo, starting at
+;                        most current
+;
+(def traceargs
+  (nlambda (args)
+          (cond ((and args $$functions-in-trace$$)
+                 (let ((name (car args))
+                       (amt (cond ((numberp (cadr args)) (cadr args))
+                                  (t 1))))
+                      (do ((fit $$functions-in-trace$$ (cdr fit))
+                           (fat $$funcargs-in-trace$$ (cdr fat)))
+                          ((null fit))
+                          (cond ((eq name (car fit))
+                                 (cond ((zerop (setq amt (1- amt)))
+                                        (return (car fat))))))))))))
+
+;--- T-tracedump-recursive
+; since the lists of functions being traced and arguments are in the reverse
+; of the order we want to print them, we recurse down the lists and on the
+; way back we print the information.
+;
+(def T-tracedump-recursive
+  (lambda ($$functions-in-trace$$ $$funcargs-in-trace$$)
+         (cond ((null $$functions-in-trace$$))
+               (t (T-tracedump-recursive (cdr $$functions-in-trace$$)
+                                         (cdr $$funcargs-in-trace$$))
+                  (T-traceenter (car $$functions-in-trace$$)
+                                (car $$funcargs-in-trace$$))))))
+
+
+
+;--- T-traceenter - funnm : name of function just entered
+;                - count : count to print out
+;      This routine is called to print the entry banner for a
+;      traced function.
+;
+(def T-traceenter
+  (lambda (name args)
+         (prog (count indent)
+               (cond ((not $tracemute)
+                      (setq count 0 indent 0)
+                      (do ((ll $$functions-in-trace$$ (cdr ll)))
+                          ((null ll))
+                          (cond ((eq (car ll) name) (setq count (1+ count))))
+                          (setq indent (1+ indent)))
+                      
+                      (T-traceindent indent)
+                      (T-print count)
+                      (T-patom '" <Enter> ")
+                      (T-print name)
+                      (T-patom '" ")
+                      (cond ((setq count (T-get name 'trace-printargs))
+                             (funcall count args))
+                            (t (funcall trace-printer args)))
+                      (T-terpr))))))
+
+(def T-traceexit
+  (lambda (name res)
+         (prog (count indent)
+               (cond ((not $tracemute)
+                      (setq count 0 indent 0)
+                      (do ((ll $$functions-in-trace$$ (cdr ll)))
+                          ((null ll))
+                          (cond ((eq (car ll) name) (setq count (1+ count))))
+                          (setq indent (1+ indent)))
+                      
+                      
+                      (T-traceindent indent)
+                      (T-print count)
+                      (T-patom " <EXIT>  ")
+                      (T-print name)
+                      (T-patom "  ")
+                      
+                      (cond ((setq count (T-get name 'trace-printres))
+                             (funcall count res))
+                            (t (funcall trace-printer res)))
+                      
+                      (T-terpr))))))
+
+
+;--- Trace-printer
+;  this is the default value of trace-printer.  It prints a form after
+; binding prinlevel and prinlength.
+;
+(def Trace-print
+   (lambda (form)
+      (let ((prinlevel trace-prinlevel)
+           (prinlength trace-prinlength))
+        (T-print form))))
+
+; T-traceindent
+; - n   :  indent to column n
+
+(def T-traceindent
+  (lambda (col)
+         (do ((i col (1- i))
+              (char '| |))
+             ((< i 2))
+             (T-patom (cond ((eq char '| |) (setq char '\|))
+                            (t (setq char '| |)))))))
+; from toplevel.l:
+;
+;--- read and print functions are user-selectable by just
+; assigning another value to top-level-print and top-level-read
+;
+(declare (special top-level-read top-level-print))
+
+(defmacro top-print (&rest args)
+   `(cond (top-level-print (funcall top-level-print ,@args))
+         (t (T-print ,@args))))
+
+(defmacro top-read (&rest args)
+   `(cond ((and top-level-read
+               (T-getd top-level-read))
+          (funcall top-level-read ,@args))
+         (t (T-read ,@args))))
+
+
+; trace-break  - this is the trace break loop
+(def trace-break
+  (lambda nil
+        (prog (tracevalread piport)
+              (T-terpr) (T-patom '"[tracebreak]")
+       loop   (T-terpr)
+              (T-patom '"T>")
+              (T-drain)
+              (cond ((or (eq nil (setq tracevalread
+                                        (car
+                                         (errset (top-read nil nil)))))
+                         (and (dtpr tracevalread)
+                              (eq 'tracereturn (car tracevalread))))
+                       (T-terpr)
+                       (return nil)))
+              (top-print (car (errset (T-eval tracevalread))))
+              (go loop))))
+
+
+(def T-levprint
+  (lambda (x)
+         ((lambda (prinlevel prinlength)
+                 (T-print x))
+          3 10)))
+
+                      
+(eval-when (eval)
+  (apply 'sstatus `(uctolc ,old-uctolc-value))
+  (setq readtable old-read-table-trace)
+  )
diff --git a/usr/src/ucb/lisp/lisplib/vector.l b/usr/src/ucb/lisp/lisplib/vector.l
new file mode 100644 (file)
index 0000000..c565547
--- /dev/null
@@ -0,0 +1,273 @@
+(setq rcs-vector-
+   "$Header: vector.l 1.5 83/07/30 15:35:51 layer Exp $")
+
+;; vector handling functions   -[Sun Jun 19 15:09:14 1983 by jkf]-
+;; [also contains closure functions]
+;;
+;; preliminary.  this is subject to change at any moment.
+;; Don't use the functions in this file!!      --jkf
+;;
+;; contains functions:
+;;  vector{,i-byte,i-word,i-long}   : create and initialize
+;;  vref{,i-byte,i-word,i-long}         : reference
+;;  vset{,i-byte,i-word,i-long}         : set
+;;  vsize      -- must write
+;;  vsize-word
+;;  vsize-byte 
+;;
+;; references external functions
+;;  new-vector{,i-byte,i-word,i-long
+;;
+;; references internal functions:
+;;  int:vref 'vect 'index 'class
+;;  int:vset 'vect 'index 'value 'class
+;;  int:vsize 'vect
+
+;--- vector
+;  call is (vector elmt0 elmt1 ... elmtn)
+; creates an n-1 size vector and initializes
+;
+(defmacro vector-macro (create class)
+   `(let ((vec (,create n)))
+      (do ((from n to)
+          (to (1- n) (1- to)))
+         ((< to 0))
+         (int:vset vec to (arg from) ,class))
+      vec))
+
+(defun vector n (vector-macro new-vector 3))
+(defun vectori-byte n (vector-macro new-vectori-byte 0))
+(defun vectori-word n (vector-macro new-vectori-word 1))
+(defun vectori-long n (vector-macro new-vectori-long 2))
+
+;--- vref
+; refernces an element of a vector
+;   (vref 'vect 'index)
+;
+(defmacro vref-macro (vector index predicate limit class)
+   `(cond ((not (,predicate ,vector))
+         ,(cond ((eq predicate 'vector)
+                 `(error "vref: non vector argument " ,vector))
+                (t `(error "vref: non vectori argument " ,vector))))
+        ((not (fixp ,index))
+         (error "vref: non fixnum index " ,index))
+        ((or (< ,index 0) (not (< ,index ,limit)))
+         (error "vref: index out of range " ,index ,vector))
+        (t (int:vref ,vector ,index ,class))))
+
+(defun vref (vect ind)
+   (vref-macro vect ind vectorp (vsize vect) 3))
+
+(defun vrefi-byte (vect ind)
+   (vref-macro vect ind vectorip (vsize-byte vect) 0))
+(defun vrefi-word (vect ind)
+   (vref-macro vect ind vectorip (vsize-word vect) 1))
+(defun vrefi-long (vect ind)
+   (vref-macro vect ind vectorip (vsize vect) 2))
+
+
+;--- vset
+; use:
+;      (vset 'vector 'index 'value)
+;
+(defmacro vset-macro (vector index value predicate limit class)
+   `(cond ((not (,predicate ,vector))
+         ,(cond ((eq predicate 'vector)
+                 `(error "vset: non vector argument " ,vector))
+                (t `(error "vset: non vectori argument " ,vector))))
+        ((not (fixp ,index))
+         (error "vset: non fixnum index " ,index))
+        ((or (<& ,index 0) (not (<& ,index ,limit)))
+         (error "vset: index out of range " ,index ,vector))
+        (t (int:vset ,vector ,index ,value ,class))))
+
+(defun vset (vect ind val)
+   (vset-macro vect ind val vectorp (vsize vect) 3))
+
+(defun vseti-byte (vect ind val)
+   (vset-macro vect ind val vectorip (vsize-byte vect) 0))
+
+(defun vseti-word (vect ind val)
+   (vset-macro vect ind val vectorip (vsize-word vect) 1))
+
+(defun vseti-long (vect ind val)
+   (vset-macro vect ind val vectorip  (vsize vect) 2))
+
+
+;;; vector sizes
+
+;--- vsize :: size of vector viewed as vector of longwords
+;
+(defun vsize (vector)
+   (if (or (vectorp vector) (vectorip vector))
+      then (int:vsize vector 2)
+      else (error "vsize: non vector argument " vector)))
+
+(defun vsize-word (vectori)
+   (if (vectorip vectori)
+      then (int:vsize vectori 1)
+      else (error "vsize-word: non vectori argument " vectori)))
+
+(defun vsize-byte (vectori)
+   (if (vectorip vectori)
+      then (int:vsize vectori 0)
+      else (error "vsize-byte: non vectori argument " vectori)))
+
+;; vector property list functions
+;;
+(defun vget (vector ind)
+   (let ((x (vprop vector)))
+      (if (dtpr x)
+        then (get x ind))))
+
+;--- vputprop :: store value, indicator pair on property list
+; if a non-dtpr is already there,  make it the car of the list
+;
+(defun vputprop (vector value ind)
+   (let ((x (vprop vector)))
+      (if (not (dtpr x))       
+        then (setq x (ncons x))
+             (vsetprop vector x))
+      (putprop x value ind)))
+
+            
+;; closures
+;
+;- closures are implemented in terms of vectors so we'll store the
+; code here for now
+;  a closure is a vector with leader field eq to 'closure'
+; the 0th element of a closure vector is the functional form
+; to funcall
+; then the elements go in triplets
+;                      1 is the symbol name
+;                          either
+;      2 is nil                        2 is a pointer to a vector
+;      3 is the saved value            3 is a fixnum index into the vector
+;       ^                                 ^
+;       |---- the simple case             |-- when we are sharing a value
+;                                             slot, this points to the
+;                                             value slot
+;
+; the size of the vector tells the number of variables.
+;
+
+;--- closure :: make a closure
+; form (closure 'l_vars 'g_fcn)
+; l_vars is a list of symbols
+; g_fcn is a functional form, either a symbol or a lambda expression
+; alist is a list of what has been already stored so far.
+;   it will always be non nil, so we can nconc to it to return values.
+;
+(defun make-fclosure-with-alist (vars fcn alist)
+   (cond ((not (or (null vars) (dtpr vars)))
+         (error "fclosure: vars list has a bad form " vars)))
+   
+   (let ((vect (new-vector (1+ (length vars)) nil 'fclosure)))
+      (do ((xx vars (cdr xx))
+          (val)
+          (sym)
+          (i 1 (1+ i)))
+         ((null xx)
+          (setf (vref vect 0) fcn)     ; store the function to call
+          vect)
+         (setq sym (car xx))
+         (cond ((not (symbolp sym))
+                (error "fclosure: non symbol in var list " sym)))
+
+         ; don't allow the variable nil to be closed over
+         (cond ((null sym)
+                (error "fclosure: you can't close over nil " vars)))
+
+         ; if the fclosure variable has already been given slot, use
+         ; it, else make a new one
+         (cond ((null (setq val (assq sym alist)))
+                  ; if the variable is bound use it's current value,
+                  ; else use nil
+                  (cond ((setq val (boundp sym))
+                         (setq val (cdr val))))
+                  ; generate a new closure variable object
+                  (setq val (cons sym (cons val (copyint* 0))))
+                  ; remember this value for later fclosures
+                  (nconc alist (list val))))
+         (setf (vref vect i) val))))
+   
+
+
+;--- fclosure :: generate a simple fclosure
+; 
+(defun fclosure (vars func)
+   (make-fclosure-with-alist vars func (list nil)))
+
+(defun fclosure-list n
+   (cond ((not (evenp n))
+         (error "fclosure-alist: not given an even number of arguments: "
+                (listify n))))
+   (do ((i 1 (+ i 2))
+       (alist (list nil))
+       (res))
+       ((> i n) (nreverse res))
+       (push (make-fclosure-with-alist (arg i) (arg (1+ i)) alist) res)))
+
+(defun fclosurep (fclosure)
+   (and (vectorp fclosure)
+       (eq 'fclosure (vprop fclosure))))
+(defun fclosure-alist (fclosure)
+   (cond ((fclosurep fclosure)
+         (do ((xx 1 (1+ xx))
+              (lim  (vsize fclosure))
+              (val)
+              (res))
+             ((not (< xx lim))
+              res)
+             (setq val (vref fclosure xx))
+             (push (cons (car val) (cadr val)) res)))
+        (t (error "fclosure-alist: non fclosure argument: " fclosure))))
+
+
+
+(defun fclosure-function (fclosure)
+   (and (fclosurep fclosure)
+       (vref fclosure 0)))
+
+(defun vector-dump (vect)
+   (let (size)
+      (msg "size = " (setq size (vsize vect)) ", prop= " (vprop vect) N)
+      (do ((ii 0 (1+ ii)))
+         ((not (< ii size)))
+         (msg ii ": " (vref vect ii) N ))))
+   
+       
+;--- symeval-in-fclosure :: determine the value of a symbol
+;   with respect to an fclosure.
+;
+(defun symeval-in-fclosure (fclosure symbol)
+  (cond ((not (fclosurep fclosure))
+        (error "set-in-fclosure: non fclosure first argument: " fclosure))
+       (t (do ((xx 1 (1+ xx))
+               (val)
+               (lim (vsize fclosure)))
+              ((not (< xx lim))
+               (error "symeval-in-fclosure: variable not found" symbol))
+              (setq val (vref fclosure xx))
+              (cond ((eq symbol (car val))
+                     (return (int:fclosure-stack-stuff val))))))))
+
+;--- set-in-fclosure :: set the value of a symbol in an fclosure
+;
+(defun set-in-fclosure (fclosure symbol value)
+  (cond ((not (fclosurep fclosure))
+        (error "set-in-fclosure: non fclosure first argument: " fclosure))
+       (t (do ((xx 1 (1+ xx))
+               (val)
+               (lim (vsize fclosure)))
+              ((not (< xx lim))
+               (error "set-in-fclosure: variable not found" symbol))
+              (setq val (vref fclosure xx))
+              (cond ((eq symbol (car val))
+                     (return (int:fclosure-stack-stuff val value))))))))
+
+(defmacro let-fclosed (vars function)
+  `(let ,vars (fclosure ',(mapcar #'(lambda (x) (if (atom x) x (car x))) vars)
+                       ,function)))
+               
+
diff --git a/usr/src/ucb/lisp/lisplib/version.l b/usr/src/ucb/lisp/lisplib/version.l
new file mode 100644 (file)
index 0000000..cb67d2b
--- /dev/null
@@ -0,0 +1,15 @@
+;; version.l
+;;                     -[Sat Sep 10 10:51:45 1983 by jkf]-
+;;
+;; This file is edited after every modification is made to the
+;; lisp system.
+;; Variables defined:
+;;   this-lisp-version-built: a symbols whose pname is the date when
+;;     the lisp system was build.  People who care about such things
+;;     can have their .lisprc file print it out at startup
+;;   franz-minor-version-number.  This is printed after the opus number
+;;     upon startup.  It is incremented after each fix or feature addition
+;;
+
+(setq this-lisp-version-built (status ctime)
+      franz-minor-version-number ".79")
diff --git a/usr/src/ucb/lisp/lispnews b/usr/src/ucb/lisp/lispnews
new file mode 100644 (file)
index 0000000..46766d2
--- /dev/null
@@ -0,0 +1,5558 @@
+From jkf Tue Apr 13 00:12:22 1982
+To: /na/doe/jkf/lispnews
+Subject: new features
+Status: RO
+
+ In response to requests from franz users, these enhancements have been
+made:
+
+In Lisp 38.07,  if the lisp variable 'displace-macros' is set to non-nil,
+then when a macro expansion is done by the evaluator, the resulting
+expansion replaces the original call.  This means that macro expansion
+is only done once.  
+
+In Liszt 8.03, the 'function' function is open coded.  If you have
+       (function (lambda ....))
+in your code then the lambda expression is compiled as a separate function
+and the result of the function call is a 'bcd' object which points
+to that compiled lambda.
+
+
+
+From jkf Sun Apr 18 13:16:46 1982
+To: local-lisp
+Subject: opus 38.09
+Status: RO
+
+ The new features of this version are:
+       If the load function ends up fasl'ing in a file, then load will
+  do what is necessary to insure that the new functions are linked in
+  correctly. Previously, if you turned on the transfer tables with
+  (sstatus translink on) or (sstatus translink t) and then fasl'ed in
+  functions which already existed, the old versions of the functions
+  would still be used, unless you did (sstatus translink on) yourself.
+  Now this is done automatically.
+
+      tyi now accepts a second argument which is the object to return
+  upon eof.  -1 is the default.
+
+     (pp-form 'g_obj ['p_port]) should be used instead of $prpr
+ for pretty printing a form.
+
+     The storage allocator and collector has been modified to add
+ two new data types: vector and vector immediate.  They are not in
+ their final form so I suggest that you not try to use them. 
+ However, be on the lookout for garbage collection bugs.
+
+
+
+From jkf Wed Apr 21 07:45:54 1982
+To: local-lisp
+Subject: liszt 8.04
+Status: RO
+
+  the new features of liszt 8.04 are:
+
+1) init files:
+    Before liszt begins compiling, it looks for an init file to load in.
+    It first searches in the current directory, and then it searches
+    your home directory (getenv 'HOME).
+    It looks for file names:
+       .lisztrc.o  .lisztrc.l  lisztrc.o lisztrc.l
+    It loads only the first one it finds.
+
+2) interrupt handling
+    If you interrupt liszt  (with ^C typically), it will remove its
+    temporary file and exit.
+
+3) preallocation of space
+    It preallocates space in order to reduce the number of gc's done
+    during compiling.
+
+       
+       
+
+
+From jkf Wed Apr 21 13:47:50 1982
+To: local-lisp
+Subject: lisp opus 38.10
+Status: RO
+
+ lisp will now look for a lisprc in a way similar to liszt.
+
+ It will first search in . and then in $HOME
+ It will look for the file .lisprc or lisprc ending with .o, .l and then
+just .lisprc or lisprc.
+
+ Shortly, it will only look for files ending in .l and .o since we don't
+want to encourage files with non-standard filename extensions.
+
+
+
+
+From jkf Wed Apr 21 23:40:59 1982
+To: local-lisp
+Subject: lisp opus 38.11
+Status: RO
+
+ I finally got sick of showstack and baktrace and rewrote them in lisp,
+rincorporating some of the features people have been requesting.
+Showstack now works as follows:
+       (showstack) : show all interesting forms.  Forms resulting from
+                     the trace package are not printed as well as 
+                     extraneous calls to eval.  In the form printed,
+                     the special form <**> means 'the previous expression
+                     printed'.  prinlevel and prinlength are set to 
+                     reasonable values to prevent the expression from
+                     getting too large
+       (showstack t) : same as above but print all expressions.
+       (showstack 5) : print only the first 5 expressions. of course, 5
+                     is not the only possible numeric argument.
+       (showstack lev 3) : set prinlevel to 3 before printing
+       (showstack len 4) : set prinlength to 4 before printing
+ the above arguments can be used in combination.
+
+The default value of prinlevel is showstack-prinlevel, that of prinlength
+is showstack-prinlength.  the default showstack printer is the
+value of showstack-printer (default is 'print').
+
+baktrace accepts the same arguments as showstack, but it ignores the
+prinlevel and prinlength arguments.
+
+
+
+
+From jkf Sat Apr 24 08:55:18 1982
+To: local-lisp
+Subject: lisp opus 38.12, liszt 8.05
+Status: RO
+
+  these changes and enhancements were made:
+
+1) the function 'function' in the interpreter acts just like 'quote'
+   In the compiler, 'function' will act like 'quote' unless the
+   argument is a lambda expression, in which case liszt will replace
+   the lambda expression with a unique symbol.  That unique symbol's
+   function cell will contain a compiled version of the lambda 
+   expression.   These changes will make Franz compatible with Maclisp
+   type lisps, as far as the treatment of 'function'
+
+2) Mechanisms were added to permit user written C or Fortran code to call 
+   lisp code. Everything isn't quite ready yet.
+
+3) Signal was fixed so that if you ask for a signal to be ignored, the
+   operating system will be notified.  The correct way to fork a lisp
+   is now:
+       (cond ((fork) (signal 2 (prog1 (signal 2) (wait)))))
+
+4) You can select the default function trace uses to print the arguments and
+   results.  Just lambda bind trace-printer to the name of the function
+   you want it to use.  The standard trace-printer sets prinlevel and
+   prinlength to the values of trace-prinlevel and trace-prinlength before
+   printing.  By default, trace-prinlevel is 4, and trace-prinlength is 5
+
+
+   
+
+
+From jkf Sun Apr 25 23:46:16 1982
+To: local-lisp
+Subject: lisp opus 38.13
+Status: RO
+
+  Functions 1+ and 1- are now part of the interpreter, rather than
+being made equivalent to add1 and sub1.
+
+
+
+From jkf Wed Apr 28 09:52:43 1982
+To: local-lisp
+Subject: Opus 38.14
+Status: RO
+
+  Has these new features:
+       1) the message [load filename] will appear before load
+          reads in a lisp source file.  This can be disabled by
+          setting $ldprint to nil.
+       2) a function 'truename' as been added.  It takes a port
+          and returns the name of the file associated with that port.
+          It returns a string if there is a file associated with
+          the port, otherwise it returns nil.
+
+
+
+From jkf Wed Apr 28 10:36:34 1982
+To: local-lisp
+Subject: more on opus 38.14
+Status: RO
+
+ $ldprint is lambda bound to nil during the loading of the lisprc file.
+
+
+
+
+From jkf Wed May  5 08:30:00 1982
+To: local-lisp
+Subject: opus 38.15
+Status: RO
+
+ a minor modification: 'makhunk' is now more efficient.
+
+
+From jkf Wed May  5 20:56:40 1982
+To: local-lisp
+Subject: Opus 38.16
+Status: RO
+
+ A new function was added:
+       (hunk-to-list 'h_hunk) 
+       returns the elements of h_hunk as a list.
+
+ Also, the error message printed when an oversized print name is encountered
+has been improved.
+
+
+
+From jkf Fri May  7 20:03:40 1982
+To: local-lisp
+Subject: Liszt version 8.06
+Status: RO
+
+
+ Local declarations are now supported.  You can say:
+(defun foo (a b)
+   (declare (special a))
+   ... body ...)
+
+and the special declaration for 'a' will affect the body of function
+foo only.  The 'a' which is an argument to foo will also be special
+in this case.    Declarations may be 
+ 1) at the top level, not within a function body.
+ 2) at the beginning of a  'lambda' body.
+ 3) at the beginning of a 'prog' body
+ 4) at the beginning of a 'do' body.
+
+'the beginning' means either the first, second or third form in the body.
+When the compiler is searching for declarations, it will not macroexpand.
+
+
+ Fixnum declarations now have meaning.  If you do
+       (declare (fixnum i j))
+then
+       (greaterp i  j)  will be converted to (>& i j)
+
+ The declare function is now defined in the compiler.  Previously,
+the only way to declare something was for the compiler to 'compile'
+the declaration form.  Now, if you load or fasl in a file with
+a declare statement in it, the declare statement will have the
+proper effect in the compiler.
+
+
+ (function (lambda () ...)), (function (nlambda () ...)) and
+ (function (lexpr () ...))  are all supported.
+
+
+
+From jkf Wed May 12 08:15:37 1982
+To: local-lisp
+Subject: Lisp Opus 38.17
+Status: RO
+
+ ... has a minor bug fix:  The port returned by 'fileopen' will now print
+correctly.
+
+
+
+From jkf  Tue May 25 06:18:04 1982
+Date: 25-May-82 06:17:51-PDT (Tue)
+From: jkf
+Subject: opus 38.18
+Via: ucbkim.EtherNet (V3.100 [3/27/82]); 25-May-82 06:18:04-PDT (Tue)
+To: local-lisp
+Status: RO
+
+  The msg macro will now evaluate all atom arguments except the ones 
+for carriage control (N B).  Thus if you used (msg foo) you should
+now use (msg "foo").
+
+
+
+From jkf Thu May 27 08:29:29 1982
+To: local-lisp
+Subject: liszt 8.08
+Status: RO
+
+ Fixes a bug in the code which converts generic arithmetic to fixnum only
+arithmetic.   Liszt was converting from generic to fixnum operators based on
+the first argument only due to a typo in the code.
+
+
+
+From jkf Wed Jun  9 07:25:19 1982
+To: local-lisp
+Subject: lisp Opus 38.20
+Status: RO
+
+  There is now a character macro for reading hexadecimal.
+  #x1f = #X1f = #X1F = 31
+  #x-1f = -31
+  
+
+
+From jkf Thu Jun 17 15:42:54 1982
+To: local-lisp
+Subject: Lisp Opus 38.21
+Status: RO
+
+  Has two routines for interfacing with termcap.  These routines were
+written by morris djavaher and are meant to be called by lisp programs
+which have yet to be installed.
+
+
+
+
+From jkf  Tue Jun 22 09:09:25 1982
+Date: 22-Jun-82 09:09:13-PDT (Tue)
+From: jkf
+Subject: opus 38.22
+Via: ucbkim.EtherNet (V3.120 [6/17/82]); 22-Jun-82 09:09:25-PDT (Tue)
+To: local-lisp
+Status: RO
+
+  setq with no arguments will now return nil.
+  
+
+
+From jkf  Wed Jun 30 19:05:54 1982
+Date: 30-Jun-82 19:05:32-PDT (Wed)
+From: jkf (John Foderaro)
+Subject: liszt 8.09
+Via: ucbkim.EtherNet (V3.130 [6/26/82]); 30-Jun-82 19:05:54-PDT (Wed)
+To: local-lisp
+Status: RO
+
+  liszt will now look in 12 places for an init file when it starts up.
+It will load in the first one it comes to only.
+The files it looks for are:
+
+  { ./ , $HOME } { .lisztrc , lisztrc } { .o , .l , }
+
+
+
+From jkf  Tue Sep 14 08:53:03 1982
+Date: 14-Sep-82 08:52:44-PDT (Tue)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.26
+Message-Id: <8208141553.9999@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.193 [9/6/82]) id a09999;
+       14-Sep-82 08:53:03-PDT (Tue)
+To: local-lisp
+Status: RO
+
+  Franz used to read the symbols 4dxx 4Dxx and 4Exx as 4exx.  Now it reads
+them (and other similar symbols) correctly.
+
+
+
+
+From jkf  Sat Oct  2 15:15:48 1982
+Date: 2-Oct-82 15:15:32-PDT (Sat)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.27
+Message-Id: <8209022215.10796@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.193 [9/6/82]) id a10796;
+       2-Oct-82 15:15:48-PDT (Sat)
+To: local-lisp
+Status: RO
+
+  If you set the variable top-level-print to a non nil value, then that
+value will be used by the top-level to print out the result of the
+evaluation.  This has effect in break loops too.
+  For example, if you want the pretty printer to print out the top level
+values, type  (setq top-level-print 'pp-form).
+
+
+  
+
+
+From jkf  Sun Oct  3 19:28:45 1982
+Date: 3-Oct-82 19:28:29-PDT (Sun)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.28
+Message-Id: <8209040228.9829@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.193 [9/6/82]) id a09829;
+       3-Oct-82 19:28:45-PDT (Sun)
+To: local-lisp
+Status: RO
+
+ A modification has been made to the load function.
+   Normally if you type (load 'x), the load function will first try to fasl
+the file x.o and failing that it will try to load x.l
+   If you (setq load-most-recent t),  and if x.l and x.o both exist, then
+load will fasl or load the most recently modified file.
+   The load-most-recent flag only has an effect if you type the filename
+without a trailing .l or .o.
+
+
+
+
+From jkf  Tue Oct  5 21:01:55 1982
+Date: 5-Oct-82 21:01:33-PDT (Tue)
+From: jkf (John Foderaro)
+Subject: liszt 8.12, lisp 38.29
+Message-Id: <8209060401.6358@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.193 [9/6/82]) id a06358;
+       5-Oct-82 21:01:55-PDT (Tue)
+To: local-lisp
+Status: RO
+
+  Liszt will now check that you are passing the correct number of arguments
+to functions.   As a result, some files which have compiled without
+complaint in the past may compile now with warnings or errors.  In this
+note, I'll explain what the compiler knows, what it looks for in your
+program, and how you can help the compiler understand your program.
+
+  For each function, liszt either knows nothing about the the number of
+arguments to a function, or it knows the minimum number of arguments, or the
+maximum number of arguments, or both the minimum and maximum number of
+arguments.   This information comes about in one of three ways:
+  1) it is known when liszt starts (by virtue of a value stored under the
+     fcn-info indicator on a function's property list)
+  2) it is declared by the user, either via (declare (*arginfo ...))
+     or (declare (*args ...)) [see below]
+  3) it is determined when a (lambda) function is compiled.
+     When a lambda is compiled, the compiler can easily figure out the
+       minimum and maximum number of arguments.
+     When an nlambda or lexpr function is compiled, the compiler doesn't
+     make a guess as to how many arguments are expected.  The user should
+     use the (declare (*args ...)) form to tell the compiler how many
+     arguments are expected.
+     For lexpr's generated via 'defun' using &optional and &rest keywords,
+     the correct declaration is generated automatically.
+Once liszt determines the number of arguments to a function, it uses that
+information to check that the function is called with the correct number of
+arguments.  It does not check calls to the function that occured before it
+determined the correct number of arguments.  [This backward checking will
+be added sometime in the future.]
+
+  If liszt finds that a function is called with the wrong number of
+arguments, it prints an informative message.  That message is a error if the
+function being called is one which is open coded by the compiler. The
+message is a warning otherwise.  The reason for the distinction is that
+you are free to redefine functions not open coded by the compiler. If the
+number of arguments is not correct, it may just be that the compiler's
+database and your code are refering to two different functions.
+If you redefine system functions, you should use the
+(declare (*arginfo ...)) form to let the compiler know about the number
+of arguments expected by your version of the functions.
+
+  You can declare the number of arguments to functions using this form
+
+(declare (*arginfo (fcnname1 min1 max1) (fcnname2 min2 max2) ...))
+  where each min or max is either a fixnum or nil (meaning "I don't know")
+  
+for example, here are some `correct' declarations:
+
+(declare (*arginfo (read 0 2) (cons 2 2) (boole 3 nil) (append nil nil)))
+  
+ explanation:
+   (read 0 2) means that the function read expects between 0 and 2
+       arguments (inclusive).
+   (cons 2 2) means that cons expects 2 arguments.
+   (boole 3 nil) means that boole expects at least 3 arguments.
+   (append nil nil) means that append expects any number of arguments,
+      this is equivalent to (append 0 nil).
+      
+
+The *arginfo declaration is usually made at the top level of a file.
+
+To declare the argument characteristics of the current function being
+compiled use the '*args' declaration. It looks somewhat like the
+*arginfo declaration.
+
+It is best explained with examples
+
+(def read
+   (lexpr (n)
+       (declare (*args 0 2))
+       ... code for read
+       ))
+
+(def process
+  (nlambda (x)
+      (declare (*args 1 3))
+      ... code for process
+      ))
+
+Note: the *args declaration is not needed for lambda's.
+
+
+
+  If you get an error or warning which you believe is incorrect, it is
+probably due to an incorrect database entry.  Please let me know and I will
+fix it immediately.   I expect that there will be quite a few of these
+errors because much of the database was built by hand.
+
+
+     
+
+
+
+From jkf  Fri Oct  8 12:55:45 1982
+Date: 8-Oct-82 12:55:31-PDT (Fri)
+From: jkf (John Foderaro)
+Subject: lisp 38.30, liszt 8.13
+Message-Id: <8209081955.4140@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.193 [9/6/82]) id a04140;
+       8-Oct-82 12:55:45-PDT (Fri)
+To: local-lisp
+Status: RO
+
+There are now three new functions for dealing with processes:
+  *process
+  *process-send
+  *process-receive
+
+ These functions are designed to replace the 'process' function, which, due
+to its nlambda'ness, was difficult to use.  All of the above functions
+are lambda's or lexpr's.
+
+  See chapter 6 of the manual (its on-line) for the details of these
+functions.  This is a quick summary:
+
+  (*process-send 'st_command)
+  tells the shell to run the command st_command concurrently, and returns
+  a write-only port.  Characters written to this port will appear at
+  the standard input of st_command.
+  example:
+     (setq p (*process-send "mail jkf"))
+     (print 'HiThere p)
+     (close p)
+
+     
+  (*process-receive 'st_command)
+  tells the shell to run st_command concurrently, and returns a
+  read-only port.  Characters written to the standard output by
+  st_command will be available by reading from the given port.
+  Characters written on the standard error by st_command will
+  appear on lisp's the standard error (the terminal most likely).
+  example:
+    ; to see if foo is logged in:
+    (setq p (*process-receive "u"))
+    (do ((user (read p '**eof**) (read p '**eof**)))
+        ((eq '**eof** user) (print 'Not-Logged-In))
+       (cond ((eq 'foo user) (print 'Is-Logged-In))))
+    (close p)
+
+
+  (*process 'st_command ['g_readp ['g_writep]])
+  this is the general function which process, *process-send and
+  *process-receive call.  If called with one argument it
+  starts the new process and waits for it to end, e.g:
+  (*process (concat "vi " filename))
+  In this case *process return the exit code of the process.
+
+  The g_readp and g_writep arguments, if given, tell *process to
+  run the process concurrently.  If g_read is non nil then
+  *process will return a port just like *process-receive.
+  If g_writep is non-nil, then *process will set up a pipe like
+  *process-send.
+  *process will return a list of the form
+    (readport writeport process-id)
+    where readport and writeport will only be a port if g_readp
+    or g_writep are non nil.
+
+
+ A little know fact about processes is that  a process, once started,
+cannot die and disappear until its parent asks about its status.
+Take the mail example given above:
+     (setq p (*process-send "mail jkf"))
+     (print 'HiThere p)
+     (close p)
+after the mail process finishes it work, it will attempt to die, returning
+an integer called the 'exit status'.  However until the lisp program
+asks about its status the mail process will remain in existence
+in a Zombie state, somewhere between life and death. ps will show this:
+
+  PID TT STAT  TIME COMMAND
+ 3876 p0 Z     0:01 <exiting>
+
+A user is only allowed a small number of processes, so if you continue
+to generate processes and leave them around as Zombies, you will eventually
+run out of processes.  The way to let the Zombie die is to call
+the wait function, e.g.
+    -> (wait)
+    (3876 . 0)
+    -> 
+this says that process 3876 died with exit status 0.
+
+Also, when you exit lisp the shell will clean up the Zombies.
+
+If you start a  process with (*process "vi foo") then lisp will wait
+for it to complete before continuing, so you don't have to worry about
+Zombies.  You only have to worry if you run a process concurrently,
+such as when you use *process-send or *process-receive.
+
+      
+       
+      
+
+
+
+From jkf  Tue Oct 12 10:44:22 1982
+Date: 12-Oct-82 10:43:52-PDT (Tue)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.31
+Message-Id: <8209121744.29800@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.220 [10/11/82])
+       id A29800; 12-Oct-82 10:44:22-PDT (Tue)
+To: local-lisp
+Status: RO
+
+  new function:  (time-string ['x_time])
+    if given no arguments, it returns the current time as a string.
+
+    if given an argument, x_time, then it converts that argument to
+      a time string and returns that string.
+      The argument should represent the number of seconds since
+      Jan 1, 1970 (GMT).
+
+  note that this makes (status ctime) obsolete.
+
+
+From jkf  Tue Oct 12 14:35:26 1982
+Date: 12-Oct-82 14:34:10-PDT (Tue)
+From: jkf (John Foderaro)
+Subject: also in opus 38.31
+Message-Id: <8209122135.5086@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.220 [10/11/82])
+       id A05086; 12-Oct-82 14:35:26-PDT (Tue)
+To: local-lisp
+Status: RO
+
+  If top-level-read is set to a non nil value, then the lisp
+top level will funcall it to read a form for evaluation.
+It will be funcalled with two arguments, a port and an eof marker.
+top-level-read will be used in break levels too.
+  Be very careful when setting top-level-read because if you set it
+to an illegal value, there is no way to correct it.
+
+
+
+
+
+From jkf  Tue Oct 19 18:54:18 1982
+Date: 19-Oct-82 18:54:02-PDT (Tue)
+From: jkf (John Foderaro)
+Subject: lisp tags
+Message-Id: <8209200154.195@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A00195; 19-Oct-82 18:54:18-PDT (Tue)
+To: franz-friends
+Status: RO
+
+  We also use vi style tags so emacs users and vi users can share the same
+tags file.  Rather than modify ctags, we use this shell script:
+
+#!/bin/csh 
+# make a tags file for lisp source files.
+# use:
+#      lisptags foo.l bar.l baz.l ... bof.l
+# generate the file 'tags'
+#
+awk -f /usr/local/lib/ltags $* | sort > tags
+
+
+where the file /usr/local/lib/ltags is
+
+/^\(DEF/       { print $2 "    " FILENAME "    ?^" $0 "$?" }
+/^\(def/       { print $2 "    " FILENAME "    ?^" $0 "$?" }
+
+
+
+From jkf  Tue Oct 19 22:50:40 1982
+Date: 19-Oct-82 22:50:29-PDT (Tue)
+From: jkf (John Foderaro)
+Subject: Lisp Opus 38.32, Liszt 8.14
+Message-Id: <8209200550.3968@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A03968; 19-Oct-82 22:50:40-PDT (Tue)
+To: local-lisp
+Status: RO
+
+
+Topic 1:
+    liszt can now autoload macros.   If liszt encounters a symbol without
+    a function definition but with a macro-autoload indicator on the
+    property list, then the value of the indicator is a file to load which
+    should define the macro.
+
+    The interpreter's undefined function handler will also look for
+    macro-autoload properties, thus you needn't give a symbol both an
+    autoload and a macro-autoload property.
+
+    The default lisp contains macro-autoload properties for the macros
+    defstruct, loop and defflavor.
+
+Topic 2:
+    It is now possible to define 'compiler only macros' or cmacros.
+    A cmacro acts like a normal macro, but will only be used by the
+    compiler.   A cmacro is stored on the property list of a
+    symbol under the indicator 'cmacro'.    Thus a function can
+    have a normal definition and a cmacro definition.
+    The macro 'defcmacro' has a syntax identical to 'defmacro' and
+    creates cmacros instead of macros.
+    For an example of the use of cmacros, see the definitions
+    of nthcdr and nth in /usr/lib/lisp/common2.l
+
+ Topic 3:
+    If the form (foo ...) is macro expanded and the result also begins
+    with the symbol foo, then liszt will stop macro expanding (previously
+    it got into an infinite loop).
+    
+ Topic 4:
+    The function nth has been added to Franz.
+    (nth 'x_index 'l_list)
+    returns the nth element of l_list, where the car of the list
+    is accessed with (nth 0 'l_list)
+
+    The macros (push 'g_value 'g_stack), and
+              (pop 'g_stack ['g_into])
+    have been added to franz.
+    typical uses
+      (setq foo nil)
+      (push 'xxx foo)
+      (push 123 foo)
+      now foo = (123 xxx)
+      (pop foo) returns 123
+      now foo = (xxx)
+      (pop foo yyy) returns xxx and sets yyy to xxx
+
+      
+ Topic 5:
+    The version of Flavors written at Mit for Franz have been transported
+    here.  Flavors is a system for doing object oriented programming in
+    lisp.  The documentation for flavors in the Lisp Machine manual
+    from Mit.  Since Lisp Machine manuals are rather scarce around here,
+    perhaps we can find someone to make copies of the flavor chapter for
+    those interested in it.  There is a description of the unique
+    features of the Franz Flavors in /usr/lib/lisp/flavors.usage.
+    As mentioned above, the flavors code will be autoloaded
+    when you call 'defflavor' for the first time.
+    Our local flavors expert is Eric Cooper (r.ecc).
+    
+    
+    
+
+
+
+From jkf  Fri Oct 22 15:46:51 1982
+Date: 22-Oct-82 15:46:32-PDT (Fri)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.34
+Message-Id: <8209222246.5610@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A05610; 22-Oct-82 15:46:51-PDT (Fri)
+To: local-lisp
+Status: RO
+
+
+  Franz lisp now has a form of closure called an fclosure.  A fclosure is a
+compromise between a funarg and the type of functional object that we
+currently have in Franz. In this short note, I'll explain through examples
+what fclosures are and where you might use them, and finally describe the new
+functions.  The fclosure system was designed to be compatible with the Lisp
+Machine closures, so you may want to look at a Lisp Machine manual for more
+information.  fclosure are related to closures in this way:
+   (fclosure '(a b) 'foo) <==> (let ((a a) (b b)) (closure '(a b) 'foo))
+
+A example of the use of fclosures:
+
+->(setq counter 0)
+0
+->(setq x (fclosure '(counter) '(lambda (val) (setq counter (+ val counter)))))
+fclosure[1]
+
+The function 'fclosure' creates a new type of object called a fclosure.
+A fclosure object contains a functional object, and a set of symbols and
+values for the symbols.  In the above example, the fclosure functional
+object is (lambda (val) (setq counter (+ val counter)))
+and the set of symbols and values just contains the symbol 'counter' and
+zero, the value of counter when the fclosure was created.
+
+When  a fclosure is funcall'ed:
+  1) the lisp system lambda binds the symbols in the fclosure to their
+     values in the fclosure.
+  2) it continues the funcall on the functional object of the fclosure
+  3) finally it un-lambda binds the symbols in the fclosure and at the
+     same time stores the current values of the symbols in the fclosure.
+
+To see what that means, let us continue the example:
+-> (funcall x 32)
+32
+-> (funcall x 21)
+53
+
+Notice that the fclosure is saving the value of the symbol 'counter'.
+Each time a fclosure is created, new space is allocated for saving
+the values of the symbols.
+If we executed the same fclosure function:
+->(setq y (fclosure '(counter) '(lambda (val) (setq counter (+ val counter)))))
+fclosure[1]
+
+We now have two independent counters:
+-> (funcall y 2)
+2
+-> (funcall y 12)
+14
+-> (funcall x 3)
+56
+
+To summarize:
+
+(fclosure 'l_vars 'g_funcobj)
+ l_vars is a list of symbols (not containing nil)
+ g_funcobj is lambda expression or a symbol or another fclosure
+
+  examples: (fclosure '(foo bar baz) 'plus)
+            (fclosure '(a b) #'(lambda (x) (plus x a))) notice the #'
+                       which will make the compiler compile the
+                       lambda expression.
+
+
+There are time when you want to share variables between fclosures.
+This can be done if the fclosures are created at the time times using
+fclosure-list:
+
+(fclosure-list 'l_vars1 'g_funcobj1 ['l_vars2 'g_funcobj2 ... ...])
+  This creates a list of closures such that if a symbol appears in
+  l_varsN and l_varsM then its value will be shared between the
+  closures associated with g_funcobjN and g_funcobjM.
+
+  example: -> (setq x (fclosure-list '(a) '(lambda (y) (setq a y))
+                                    '(c a) '(lambda () (setq c a))))
+           (fclosure[4] fclosure[7])
+          -> (funcall (car x) 123)   ; set the value of a in the 1st fclosure
+          123
+          -> (funcall (cadr x))     ; read the same value in the 2nd fclosure
+          123
+
+
+Other fclosure functions:
+
+(fclosure-alist 'c_fclosure)
+  returns an assoc list giving the symbols and values in the fclosure
+
+(fclosurep 'g_obj)
+  returns t iff g_obj is a fclosure
+
+(fclosure-function 'c_fclosure)
+  returns the functional object of the fclosure
+
+
+
+Note: If a throw (or error) occurs during the evaluation of a fclosure,
+ which passes control out of the fclosure, then current values of the
+ symbols will not be stored.   This may be a bug.  We could set up
+ an unwind-protect, but it would then take longer to funcall
+ a fclosure.  If you think an unwind protect is important, let me know.
+
+Note 2: you can also 'apply' a fclosure.
+
+
+
+  
+
+
+From jkf  Sat Oct 23 08:58:07 1982
+Date: 23-Oct-82 08:57:53-PDT (Sat)
+From: jkf (John Foderaro)
+Subject: more on closures
+Message-Id: <8209231558.21572@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A21572; 23-Oct-82 08:58:07-PDT (Sat)
+To: local-lisp
+Status: RO
+
+  I sent the maryland people the flavors.usage file from mit so that they
+could compare their implementation with mit's.   What follows is their
+analysis.   Some of the differences between the two versions is due to
+different schemes for getting around the fact that franz didn't have a form
+of closure.   RZ has indicated that now that franz has fclosures, it may be
+possible to use more of the 'official' lisp machine flavor code.  fclosures
+will probably affect the maryland implementation too:
+Date:     22 Oct 82 15:39:18 EDT  (Fri)
+From:     Liz Allen <liz.umcp-cs@UDel-Relay>
+Subject:  flavors
+To:       jkf at Ucb-C70
+Via:  UMCP-CS; 23 Oct 82 9:09-EDT
+
+Wow, implementing closure in one day is amazing.  We had thought
+about writing some kind of closure...  We've been discussing how
+having closures would affect our code.  It might make it easier to
+read and modify, but it might be less efficient.  Can you tell us
+how your implementation works and what it looks like to a user?
+
+About the MIT implementation.  Ours is probably better in a couple
+of respects but probably loses a couple of places, too.  Pros:
+
+       1.  With ours, there is no need to discard instances when
+       redefining a flavor.  The only time this would be necessary
+       is if the instance variables change which rarely happens
+       since methods change much more often than the instance
+       variables.  Without a structure editor, you tend to reload the
+       file containing flavors in order to change a method.
+
+       2.  We can compile files with flavors (he didn't say if you
+       can compile MIT's Franz flavors) and when they are compiled
+       they run *fast*.  Most of the overhead occurs at combine
+       time and compiled flavors shouldn't have to be recombined.
+
+       3.  We use hunks to store instance variables (actually, an
+       instance is a hunk whose cxr 0 is the name of the flavor and
+       whose cxr n (> 0) are the values of instance variables).  We
+       pay a price at combine time since instance variable references
+       in method code are replaced with cxr and rplacx calls (but MIT
+       pays the same price in putting hash calls in the methods), but
+       we win over MIT since the cxr calls are much faster than the
+       hash table calls.  We do have to have "ghost" methods which
+       are copies of methods containing different cxr calls when the
+       referenced variables of a method don't align in flavors
+       which inherit the method.  This, however, happens only
+       rarely.
+
+       4.  We handle getting and setting instance variables better
+       than the MIT implementation -- we don't need to send a message
+       and the syntax is much better.  We recently added the
+       functions << and >> which get and set instance variables, eg:
+
+               (<< foo 'instance-var)
+       and
+               (>> foo 'instance-var 'value)
+
+       where foo is a flavor instance.
+
+       5.  Our describe function has a hook which (if the variable
+       *debugging-flavors* is set to non-nil) allows the user to
+       follow pointers to any instances referenced in the describe.
+       This is done by assigning to a variable (made from its unique
+       id) the value of the instance.
+
+Cons:
+
+       1.  They implement more things from Lisp Machine flavors
+       (like wrappers/whoppers, init-keywords), but we really haven't
+       found the need for them.  We implement less closely to LM
+       flavors, but in a way that's better suited to Franz Lisp.
+
+       2.  We didn't implement the method table as a hash table, but
+       there's no reason why we couldn't.
+
+       3.  Things we don't have, but could easily implement include:
+       describe-method, defun-method/declare-flavor-instance-variables,
+       and storing flavor information in hunks instead of on the
+       property lists.
+
+       4.  We don't handle method types like :and and :or.  We just
+       have primary/untyped methods and :before and :after daemons.
+
+We have people reading our documentation.  After we get some feedback
+from them, we'll send the tape and docs to you.  That should be early
+next week.
+
+                               -Liz Allen and Randy Trigg
+
+
+
+
+
+
+
+From jkf  Mon Oct 25 12:56:59 1982
+Date: 25-Oct-82 12:55:44-PDT (Mon)
+From: jkf (John Foderaro)
+Subject: lisp Opus 38.35, liszt 8.15
+Message-Id: <8209251956.17542@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A17542; 25-Oct-82 12:56:59-PDT (Mon)
+To: local-lisp
+Status: RO
+
+
+New features:
+ 1) tilde-expansion:  franz will now expand filenames which begin with ~
+       just like csh does.  It will only do the expansion if
+       the symbol tilde-expansion has a non-nil value.  The default
+       value for tilde-expansion is t.
+       These functions do tilde expansion: If I've left any out, let
+       me know:
+        load, fasl, infile, outfile, fileopen, probef, cfasl, ffasl, chdir
+        sys:access, sys:unlink [these are new functions, see below]
+
+ 2) liszt will remove its temporary file if given a SIGTERM signal
+    (SIGTERM is sent by default when you give the kill command from the shell)
+
+ 3) load will now print a helpful message if an read error occurs when it
+    is reading a file.
+    
+ 4) new functions:
+
+     (lexpr-funcall 'function 'arg1 ... 'argn)
+        This is a cross between funcall and apply.
+       The last argument, argn, must be a list (possibly empty).
+       The element of list argn are stacked and then the function is
+       funcalled.
+       For example:
+       (lexpr-funcall 'list 'a 'b 'c '(d e f))
+       is the same as
+       (funcall 'list 'a 'b 'c 'd 'e 'f)
+       
+       Also
+       (lexpr-funcall 'list 'a 'b 'c nil)
+       is the same as
+       (funcall 'list 'a 'b 'c)
+       
+     (tilde-expand 'st_filename)
+     returns: symbol whose pname is the filename, with a leading tilde
+            expanded.  if st_filename doesn't begin with a tilde, it
+            just returns st_filename
+
+     (username-to-dir 'st_name)
+     returns: the home directory of the given user, if that user exists.
+             Saves old information so doesn't have to keep searching
+             the passwd file.
+
+     Some low level system functions.  These are listed here for completeness.
+     The perform a function from the unix library (see the unix manual
+      for details).
+     (sys:getpwnam 'st_username)
+       return passwd file info.
+     (sys:access 'st_file 'x_mode)
+     (sys:unlink 'st_file)
+
+
+Bug fixes:
+  1) patom will handle prinlevel and prinlength correctly.
+  2) it is now safe for an interpreted function to redefine itself.
+  3) the information return by 'evalframe' about a funcall'ed function
+     is now correct.
+
+  
+  
+
+
+
+From jkf  Mon Oct 25 14:57:00 1982
+Date: 25-Oct-82 14:56:25-PDT (Mon)
+From: jkf (John Foderaro)
+Subject: 'if' macro: request for comments
+Message-Id: <8209252157.21567@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A21567; 25-Oct-82 14:57:00-PDT (Mon)
+To: local-lisp
+Status: RO
+
+  Would anyone object if we added a macro called 'if' to the default franz
+system?   'if' is a common name and I want to make sure that it doesn't
+break any existing code before I add it.
+
+Some background:
+ At mit the 'if' macro is used all over the place.
+ Its form is
+       (if <predicate> <then-expr> [ <else-expr>])
+       
+ I've always felt that macros should make the code more readable and
+ that the 'if' macro makes code more obscure because it isn't easy
+ to tell in complicated 'if' expressions where the <then-expr>
+ and <else-expr>'s begin.  Also, there is no provision for
+ an 'elseif' expression.
+
+ I wrote a macro called 'If' which uses keywords to separate clauses.
+ (If <pred> 
+    then <then-expr> 
+  [elseif <pred> then <then-expr>]* 
+  [else <else-expr>])
+
+ These two macros are not incompatible.  one macro could do the job
+ of both.  There is an ambigous case:
+       (if p then x) could be (cond (p then) (t x))
+                       or (cond (p x))
+ but it isn't likely that 'if' macro users would write something like
+ that.
+
+Thus I propose that we add a macro, if, which act's like 'If' if
+its second arg is 'then' or like 'if' it the second arg is not 'then'
+and there are two or three arguments.  Other cases would cause
+an error.
+
+
+       
+
+
+From jkf  Mon Oct 25 22:37:24 1982
+Date: 25-Oct-82 22:37:09-PDT (Mon)
+From: jkf (John Foderaro)
+Subject: opus 38.36
+Message-Id: <8209260537.1666@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A01666; 25-Oct-82 22:37:24-PDT (Mon)
+To: local-lisp
+Status: RO
+
+  I've added the 'if' macro to franz.  If you have any objections, it is still
+not too late to voice them.
+  I've also defined 'If' to be the same as 'if'.
+
+  As I mentioned in my earlier request for comments, the 'if' macro is a
+cross between the mit version and a locally written version using keywords.
+The following documentation describes the various forms.
+As you know, you can test out the 'if' macro by using apply. for example:
+
+=> (apply 'if '(if a then b c  elseif d thenret else e))
+(cond (a b c) (d) (t e))
+
+
+;
+;  This macro is compatible with both the crufty mit-version and
+; the keyword version at ucb.
+;
+;  simple summary:
+;   non-keyword use:
+;      (if a b) ==> (cond (a b))
+;      (if a b c d e ...) ==> (cond (a b) (t c d e ...))
+;   with keywords:
+;      (if a then b) ==> (cond (a b))
+;      (if a thenret) ==> (cond (a))
+;      (if a then b c d e) ==> (cond (a b c d e))
+;      (if a then b c  else d) ==> (cond (a b c) (t d))
+;      (if a then b c  elseif d  thenret  else g)
+;              ==> (cond (a b c) (d) (t g))
+;
+;   
+;
+;
+; In the syntax description below,
+;    optional parts are surrounded by [ and ],
+;    + means one or more instances.
+;    | means 'or'
+;    <expr> is an lisp expression which isn't a keyword
+;       The keywords are:  then, thenret, else, elseif.
+;    <pred> is also a lisp expression which isn't a keyword.
+; 
+; <if-stmt> ::=  <simple-if-stmt>
+;             | <keyword-if-stmt>
+; 
+; <simple-if-stmt> ::=  (if <pred> <expr>)
+;                    | (if <pred> <expr> <expr>)
+; 
+; <keyword-if-stmt> ::= (if <pred> <then-clause> [ <else-clause> ] )
+; 
+; <then-clause> ::=  then <expr>+
+;                 | thenret
+; 
+; <else-clause> ::=  else <expr>+
+;                 | elseif <pred> <then-clause> [ <else-clause> ]
+
+
+
+  
+
+
+From jkf  Tue Oct 26 09:20:25 1982
+Date: 26-Oct-82 09:20:04-PDT (Tue)
+From: jkf (John Foderaro)
+Subject: no more jkfmacs
+Message-Id: <8209261620.11552@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A11552; 26-Oct-82 09:20:25-PDT (Tue)
+To: local-lisp
+Status: RO
+
+
+  Since Franz now has the push, pop, if and msg macros, there is no
+reason for jkfmacs to exist.  I've removed the code in jkfmacs and
+replaced it with a warning message which will be printed if you load it.
+  If you used the jkfmacs version of 'push' you will have to go through
+your code and switch the order of arguments.  The Franz version is
+       (push value stack)
+Also, the unpush macro, defined in jkfmacs, no longer exists: just use
+pop with one argument.
+
+
+
+From jkf  Wed Oct 27 20:35:07 1982
+Date: 27-Oct-82 20:34:25-PDT (Wed)
+From: jkf (John Foderaro)
+Subject: liszt 8.16
+Message-Id: <8209280335.27561@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A27561; 27-Oct-82 20:35:07-PDT (Wed)
+To: local-lisp
+Status: RO
+
+  Back on May 6, a modification to liszt was made which turned 'declare'
+into a user callable function which provided information to the compiler.
+The purpose of the change was to permit one to 'load' a file containing
+declarations, instead of 'include'ing it.  It turns out that this was a bad
+idea since if the compiler were to evaluate an interpreted function with
+local declarations, it would assume that those local declarations were
+describing the current file being compiled.
+   Thus declare has it old meaning: it is a no-op unless the compiler is
+compiling the form.  If one really wants to actively declare something,
+we've added the function 'liszt-declare', which looks just like declare
+but can be evaluated within the compiler.
+
+  If you are confused by all this, don't worry.  There is very little chance
+that it will affect you.
+
+
+
+From jkf  Fri Oct 29 09:34:11 1982
+Date: 29-Oct-82 09:33:59-PDT (Fri)
+From: jkf (John Foderaro)
+Subject: cmacros
+Message-Id: <8209291634.8411@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A08411; 29-Oct-82 09:34:11-PDT (Fri)
+To: local-lisp
+Status: RO
+
+  A week ago, Joe Faletti mentioned that one problem with cmacros is that if
+you redefine a function, the cmacro property stays around and thus the
+redefinition of the function isn't communicate to the compiler.
+  He suggested that whenever a function is defined (via 'def' or when fasl'ed
+in) any cmacro properties should be remprop'ed.   I've been trying to think
+of an alternative to this, but I can't think of one.  Unless someone
+has a better idea, I'll implement his suggestion.
+  This means that if you want to define the function 'foo' and a cmacro for
+'foo', the cmacro definition must appear later in the file than 'foo's
+definition.
+
+
+
+
+From jkf  Fri Oct 29 10:11:36 1982
+Date: 29-Oct-82 10:10:54-PDT (Fri)
+From: jkf (John Foderaro)
+Subject: LetS: An Expressional Loop Notation
+Message-Id: <8209291711.9176@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A09176; 29-Oct-82 10:11:36-PDT (Fri)
+To: local-lisp
+Status: RO
+
+  I've got a copy of a paper by Richard Waters (at mit) describing a system
+for writing loops in lisp (and other languages).  Basically you describe the
+loop in functional programming terms (similar to Backus's FP, or apl) and
+the LetS package converts it into an iterative form for efficient execution
+in lisp.
+  We don't have the LetS code here to play with, and we probably won't be
+able to get it for a while since our arpanet connection is hopelessly
+clogged for anything but tiny messages.   However you might be interested in
+stopping by my office and looking at the paper.
+
+
+
+
+From jkf  Fri Oct 29 12:06:47 1982
+Date: 29-Oct-82 12:06:08-PDT (Fri)
+From: jkf (John Foderaro)
+Subject: Re:  cmacros
+Message-Id: <8209291906.12141@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A12141; 29-Oct-82 12:06:47-PDT (Fri)
+To: baden, local-lisp
+In-Reply-To: Your message of 29 Oct 1982 1159-PDT (Friday)
+Status: RO
+
+  I could make it a 'Note'.  I would prefer not to make it a warning because
+such redefinition is guaranteed to occur when the compiler compiles itself
+and the lisp code part of the lisp system.
+
+
+
+From fateman Sat Oct 30 09:17:49 1982
+To: franz-friends
+Subject: fugue # 2
+Status: RO
+
+                        FUGUE Notes
+
+               An occasional publication of the
+    Franz Lisp User Group under Unix and Eunice (FUGUE)
+
+                  Number 2 (October, 1982)
+                edited by Richard J. Fateman
+                  University of California
+                     Berkeley CA 94720
+                            USA
+                      fateman@berkeley
+
+1.  Welcome!
+
+     It seems  about time to publish  the  second  of  these
+newsletters,  since  we  have  accumulated  a  number of new
+items.  We would also like to relay to others such  informa-
+tion as has been forwarded to us. The reports of projects at
+Berkeley (and elsewhere) may strike sympathetic chords  with
+other research.
+
+2.  New programs
+
+2.1.  OPS-5
+
+     OPS-5 is a "production system" written by Charles Forgy
+of  CMU.   It  appears to work just fine in Franz, and is in
+wide use.  Interested persons may obtain copies of  documen-
+tation and the program from Charles.Forgy@CMU-10A. ( Charles
+Forgy, Computer Science Department, Carnegie-Mellon  Univer-
+sity, Pittsburgh, PA  15213)
+
+It is their policy to send it to anyone who wants it free of
+charge.
+
+2.2.  GLISP
+
+     GLISP is a system which provides interesting linguistic
+features for generic operations and data abstraction.  Writ-
+ten by Gordon Novak at Stanford University,  it  was  origi-
+nally  developed for Interlisp, but has been ported to other
+lisps, including Franz.
+
+2.3.  Flavors
+
+     There are now two distinct implementations,  apparently
+with  identical  functionally,  of "flavors" as appearing in
+the MIT Lisp Machine software.  One is described in TR-1174,
+____________________
+\e9   UNIX, Eunice, Franz Lisp, may be trademarks of Bell Labs,
+SRI Int'l, and Univ. of Calif.
+
+
+
+\e9
+
+
+
+
+
+
+
+
+
+
+"Franz Flavors" by Richard J. Wood (Dept of C.S.,  Univ.  of
+Maryland,  College  Pk, MD 20742).  The other was written by
+Juan R. Loaiza of MIT, Laboratory for Computer Science.   We
+have  a  copy  of  the  latter  on-line  here, and expect to
+receive a copy of the Maryland one,  shortly.   Eric  Cooper
+here at Berkeley is in charge of the flavors situation.
+
+     There is an implementation of closures, mostly compati-
+ble  with  the Lisp Machine specification, announced by John
+Foderaro for Opus 38.33. The incompatibility is a result  of
+what  we  perceive to be a high performance penalty for eso-
+terica.
+
+2.4.  Database Interfaces
+
+     Jim Larus at UCB has cooked up interfaces to  both  the
+INGRES  relational  database  system,  and the simpler TROLL
+database system.  These will be described in his forthcoming
+MS report, along with the next item.
+
+2.5.  Cursor-control and Menus
+
+     Larus has provided an implementation of screen  manage-
+ment which uses the UNIX "curses" package for primitive win-
+dow  management.   A  menu-based  interface  has  also  been
+developed as part of this.
+
+2.6.  Vaxima and Algebraic Manipulation
+
+     A new version of vaxima, the VAX version of the MACSYMA
+algebraic  manipulation system, was released in July by UCB,
+incorporating some bug fixes, improved programs, and a large
+number  of  user-contributed subroutine libraries.  This was
+made available to test-site licensees.   Unfortunately,  MIT
+has  suspended  new  test-site  licensing since about April,
+1982.  We hope that MIT will be liberalizing  its  distribu-
+tion policy to non-commercial sites.
+
+     See the note below about MACSYMA being sold.
+
+     As a counterpoint to this, UC Berkeley has  received  a
+substantial grant from the System Development Foundation for
+work on Mathematical Representation and Manipulation,  which
+should  result in some more advanced systems for application
+of  computers  to  symbolic  mathematics.   Recruiting   for
+researchers,  staff,  and  students  is  underway  now,  and
+interested persons should contact Richard Fateman.
+
+2.7.  VLSI Design Rule Checker
+
+     Lyra, written in Lisp by Michael Arnold, is a retarget-
+able,  hierarchical,  design rule checker for VLSI circuits.
+Lyra features a rule  compiler  (also  written  in  Lisp  of
+
+
+
+
+
+
+
+
+
+
+
+
+
+course!)  which translates symbolic design rule descriptions
+to lisp code for checking the rules.  Lyra was used for  the
+RISC  project.  It  is  currently  being used extensively at
+Berkeley, and will be included in the  Fall-82  distribution
+of  of the Berkeley CAD tools.  For more information contact
+Michael Arnold or John Ousterhout at Berkeley.
+
+2.8.  Generic Arithmetic
+
+     As a proposed extension to  Franz  arithmetic,  Richard
+Fateman,  Keith  Sklower  and Scott Morrison, have written a
+simple-minded  generic  arithmetic  package  which  includes
+modules which can be loaded to support exact rational arith-
+metic, software-simulated IEEE  extended  arithmetic,  arbi-
+trary  precision floating point, complex, interval, and mul-
+tivariate polynomial. Combinations of some of these are sup-
+ported,  although  the  package is as yet incomplete in some
+areas.  The IEEE arithmetic  simulation  is  written  in  C.
+These  packages  are  probably  not in good enough shape for
+casual use by others.
+
+
+3.  New features
+
+     Various performance enhancements  and  bug  fixes  have
+been  incorporated  in  versions of Franz (now on Opus 38.33
+and the compiler, Liszt 8.14) These are mentioned  in  brief
+here;  more  details  accompany  updates  of  the system and
+manual included in the forthcoming Berkeley 4.2BSD UNIX dis-
+tribution.
+
+3.1.  Franz
+
+     We added a switch to cause the evaluator to save  macro
+expansions so they need only be expanded once.
+
+     We added vector and vector-immediate data types.
+
+     We rewrote showstack and backtrace so they  are  easier
+to use.
+
+     We made the lisp to  foreign  function  interface  more
+secure.  The system now allows foreign function to call lisp
+functions.
+
+     We added closures and support  flavors,  features  from
+the Lisp Machine.
+
+3.2.  Liszt
+
+     Liszt will check the  number  of  arguments  to  system
+functions and user defined functions.
+\e9
+
+\e9
+
+
+
+
+
+
+
+
+
+
+     Liszt supports local declarations.
+
+     Liszt will  automatically  compile  lambda  expressions
+headed by the function `function'.
+
+     Liszt supports compiler-only macros and  will  autoload
+macros if necessary.
+
+4.  MC68000
+
+     Keith Sklower and Kevin Layer have been working on  the
+MC68000  version  of  Franz  under the UNIX operating system
+(using a DUAL System 83). While the current configuration is
+a  swapping  system, the Lisp should be able to use the full
+address space of the CPU. We expect to have this system run-
+ning  on the UNIX 4.2 BSD SUN software, too. The base system
+on the DUAL, including  the  interpreter,  reader,  bignums,
+fasl, works; the compiler is being perfected.
+
+
+5.  Other Lisps
+
+     We now have, in-house tried 4  (other)  VAX  UNIX  lisp
+systems:  YLISP,  Interlisp,  PSL,  and VLISP.  We know that
+Interlisp can run also on  VMS  using  the  Eunice  package.
+Interested parties can contact David Dyer at USC-ISI.  There
+is also a version of lisp which runs  on  VMS  only,  namely
+NIL,  from  MIT, which appears to be undergoing limited dis-
+tribution.  Two other lisps under development under UNIX are
+Yale's  answer to NIL, namely "T", and Common Lisp, from CMU
+and friends.
+
+     Counting Franz, that makes  7 lisp systems for the  VAX
+computer line. Not counting variants on 2 operating systems.
+A Paen to standardization.
+
+     Dick Gabriel states some  useful  principles  for  com-
+parisons  in  the conference record of the 1982 ACM Lisp and
+Functional Programming Conference, which was held in August.
+We  understand  he  now has a collection of some 18 programs
+which he is continuing to time on various systems.
+
+6.  Work in Progress
+
+6.1.  BITGRAPH SUN AED-512
+
+     Greg Foster at UCB is working on  raster-graphics  sup-
+port in Franz for the 800 by 1000 b/w raster displays of the
+BBN Bitgraph and/or the SUN Workstation,  and  possibly  the
+color  512 by 512 AED system.  We are probably going to han-
+dle mice and Bitpad (stylus) input for pointing.  There  are
+lots  of  projects  we hear about with similar systems, e.g.
+just recently from the University of  Maryland,  using  UNIX
+
+
+
+
+
+
+
+
+
+
+
+
+
+and multiplexed files for window management of a 68000-based
+home-grown workstation.
+
+6.2.  RISC-LISP
+
+     Yes, Reduced Instruction Set Computer  fans,  who  else
+but  UCB  would  be  so bold... Carl Ponder is examining the
+issues involved in constructing a fast lisp interpreter  and
+compiler  for  the  RISC architecture.  You see, we have all
+these chips...
+
+
+7.  Work Contemplated
+
+7.1.  Fast Number Compiler
+
+     Undergraduate Jeff Cohen at  Berkeley  is  starting  to
+look  at  this.   There are several industrial concerns that
+have expressed interest in using such a system, but expected
+it to be subsidized by someone else.
+
+7.2.  IBM Franz
+
+     Even more nibbles on this one, but not yet.
+
+8.  Business News
+
+8.1.  Eunice SOLD
+
+     Some of you may have heard  that  the  Eunice  software
+package was sold by SRI to the Wollongong Group, a UNIX sup-
+port group in Palo Alto.   Prices  range  from  $2k  (educa-
+tional)  to  $5k (commercial).  Naturally this package is of
+interest beyond the availability of Franz Lisp.  We have not
+compared  this  product  to  other similar ones, but we know
+that TWG has been distributing a working Franz opus 38.
+
+     As far as alternatives to Eunice, we  are  aware  of  a
+system  developed  at  Rice University, and another by Human
+Computing  Resources  (HCR)  in  Toronto.    We   have   not
+evaluated either of these.
+
+8.2.  MACSYMA SOLD
+
+     MIT has sold exclusive rights to MACSYMA, a large alge-
+braic  manipulation  system, to Symbolics, Inc. of Cambridge
+Mass. This package runs in Franz Lisp, (among  other  Lisps)
+We  hope that soon it will again be available to educational
+institutions with VAX systems either from us  or  Symbolics,
+at a nominal charge.  We understand that commercial licenses
+(from Symbolics) for versions of MACSYMA  on  PDP-10s,  Lisp
+Machines,  etc.   will distributed at non-nominal prices and
+offered with maintenance contracts.
+
+
+
+
+
+
+
+From liz.umcp-cs@UDel-Relay Mon Nov  1 17:43:52 1982
+Date:     29 Oct 82 12:04:24 EDT  (Fri)
+From:     Liz Allen <liz.umcp-cs@UDel-Relay>
+Subject:  Re:  Flavor system
+To:       ECC.MIT-MC at Ucb-C70, FRANZ-FRIENDS at Mit-Mc
+Cc:       randy.umcp-cs at UDel-Relay
+In-Reply-To: Message of 25 October 1982 16:29-EDT from ECC@MIT-MC@Berkeley
+Via:  UMCP-CS; 30 Oct 82 5:40-EDT
+Status: RO
+
+       Date: 25 October 1982 16:29-EDT
+       From: ECC@MIT-MC@Berkeley
+       Subject:  Flavor system
+       To: FRANZ-FRIENDS at MIT-MC
+
+       Can someone give me a pointer to the Franz flavor system
+       developed by U. Maryland?  I am looking for information on how to
+       FTP the files -- what machine, whether public, what files, etc.
+
+Since the U. of Maryland is not (yet) an Arpanet host, you can't
+FTP files directly from here.  We are right now completing some
+documentation for all of our hacks -- including documentation for
+some recent improvements for our flavors system.  When that
+documentation is complete, we will be ready to distribute the
+packages developed here.  Besides flavors, this includes a top
+level called userexec which is based on INTERLISP's top level and
+a production system called YAPS similar to but more flexible than
+OPS5.
+
+We are supposed to become an Arpanet host in a few months...  (Read
+open ended period of time.)  Meanwhile, if you would like to get
+our code, mail me a tape, and I will mail it back with the code and
+documentation on it.  I'd appreciate it if someone would volunteer
+to let other folks FTP the files from their machine until we do
+become an Arpanet host.  My address is:
+
+       Liz Allen
+       Univ of Maryland
+       Dept of Computer Science
+       College Park MD 20783
+       (301) 454-4247
+       liz.umcp-cs@udel-relay
+
+                               -Liz
+
+
+
+From jkf  Wed Nov  3 15:49:29 1982
+Date: 3-Nov-82 15:48:50-PST (Wed)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.40
+Message-Id: <8210032349.16460@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A16460; 3-Nov-82 15:49:29-PST (Wed)
+To: local-lisp
+Status: RO
+
+  putprop will now put new properties at the head of the property list.
+  
+  
+
+
+From ecc@UCBARPA  Thu Nov  4 10:28:49 1982
+Date: 4-Nov-82 10:19:26-PST (Thu)
+From: ecc@UCBARPA (Eric C. Cooper)
+Subject: Lisp song
+Message-Id: <8210041819.24539@UCBARPA.BERKELEY.ARPA>
+Received: by UCBARPA.BERKELEY.ARPA (3.224 [10/16/82])
+       id A24537; 4-Nov-82 10:19:28-PST (Thu)
+Received: from UCBARPA.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A00305; 4-Nov-82 10:28:49-PST (Thu)
+To: local-lisp@kim
+Status: O
+
+[This has been forwarded from uucp through Xerox through info-lispm.]
+
+>From decvax!utzoo!utcsrgv!roderick Mon Nov  1 14:24:35 1982
+
+Another Glitch in the Call
+------- ------ -- --- ----
+   (Sung to the tune of a recent Pink Floyd song.)
+
+
+We don't need no indirection
+We don't need no flow control
+No data typing or declarations
+   Hey! Did you leave the lists alone?
+
+Chorus:
+   All in all, it's just a pure-LISP function call.
+
+We don't need no side effect-ing
+We don't need no scope control
+No global variables for execution
+   Hey! Did you leave those args alone?
+
+(Chorus)
+
+We don't need no allocation
+We don't need no special nodes
+No dark bit-flipping in the functions
+   Hey! Did you leave the bits alone?
+
+(Chorus)
+
+We don't need no compilation
+We don't need no load control
+No link edit for external bindings
+   Hey! Did you leave that source alone?
+
+(Chorus, and repeat)
+
+From jkf  Sat Nov 13 20:53:41 1982
+Date: 13-Nov-82 20:53:16-PST (Sat)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.41
+Message-Id: <8210140453.490@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.222 [10/13/82])
+       id A00490; 13-Nov-82 20:53:41-PST (Sat)
+To: local-lisp
+Status: O
+
+  added functions:
+       (remq 'g_val 'l_list) - just like remove but uses eq instead of equal
+       (command-line-args) - returns a list of the command line arguments
+               when lisp was started.  This function will return
+               only those arguments typed by the user, even if the
+               lisp was started with the autorun feature (liszt -r).
+       (sys:gethostname) - returns the name of the machine.
+       (status domain) - returns 'ucb' here.
+
+
+
+From Paul.Rosenbloom@CMU-CS-G@CMU-CS-A Sun Nov 28 08:38:06 1982
+Mail-From: CMUFTP host CMU-CS-G received by CMU-10A at 28-Nov-82 11:48:21-EST
+Date: 28 Nov 1982 11:47:28-EST
+From: Paul.Rosenbloom at CMU-CS-G at CMU-CS-A
+Subject: (random) problems
+Status: RO
+
+I am having two problems using (random) in Franz lisp.  The first problem is
+that I can't find any way to set the seed.  Every time I enter lisp, the
+generator is in the same state.  I have had to resort to cfasling a c
+procedure that calls srand() (as (random) seems to be defined in c by a call
+on rand()).  Is there a way to do this within lisp?  The other problem is
+more serious.  The generator seems to generate tight cycles for (at least)
+arguments that are small powers of 2.  For example, repeatedly executing
+(random 2) yields the sequence 01010101..., and (random 4) yields
+01230123....  These sequences apparently occur no matter to what value I set
+the seed.  Does anyone one know what I could be doing wrong, or have a
+working random number generator?
+
+
+From tim.unc@UDel-Relay Sun Nov 28 20:44:24 1982
+Status: O
+
+From tim.unc@UDel-Relay Sun Nov 28 20:27:43 1982
+Date:     28 Nov 82 22:40:14 EST  (Sun)
+From:     Tim Maroney <tim.unc@UDel-Relay>
+Subject:  rng
+To:       franz-friends at Ucb-C70
+Via:  UNC; 28 Nov 82 23:38-EST
+Status: O
+
+To the person who asked about random number generators and deficiencies
+in (random) [I can't write mail to you for some reason]:
+
+You're not doing anything wrong; that's the way the sucker works.
+One good way to get random numbers is to do the syscall that gets
+you the number of seconds since whenever-it-is, and use the mod
+function. This is especially good for getting a random one or zero,
+by using the evenp function.
+
+                                       Tim Maroney
+                                       tim@unc@udel-relay
+
+
+From jkf  Tue Nov 30 09:21:10 1982
+Date: 30-Nov-82 09:21:10-PST (Tue)
+From: jkf (John Foderaro)
+Subject: opus 38.42
+Message-Id: <8210301721.11699@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.255 [11/28/82])
+       id AA11699; 30-Nov-82 09:21:10-PST (Tue)
+To: local-lisp
+Status: O
+
+  added: (sys:link 'oldname 'newname) that what the ln program does.
+
+  changed: the order of arguments to the vset functions is now:
+       (vset 'vector 'index 'value).
+       
+       [This shouldn't affect anyone since vectors haven't been officially
+        released yet and won't be until I make one more major modification]
+
+       setf now knows about vectors.  You can say
+               (setf (vref 'vector 'index) 'value)
+       and not have to worry about the order of arguments to vset.
+
+
+
+From jkf  Tue Nov 30 10:42:00 1982
+Date: 30-Nov-82 10:42:00-PST (Tue)
+From: jkf (John Foderaro)
+Subject: Re: opus 38.42
+Message-Id: <8210301842.13143@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.255 [11/28/82])
+       id AA13143; 30-Nov-82 10:42:00-PST (Tue)
+To: jeffc, local-lisp
+In-Reply-To: Your message of 30 Nov 1982 1036-PST (Tuesday)
+Status: O
+
+  It can't do symbolic links (I've only been adding system calls that I had
+a use for).
+
+  setf is a generalized setq.  The target can be an expression which locates
+a value.  setf figures out how to store in the target.
+for example:
+
+  (setf x 3)        ==  (setq x 3)
+  (setf (car x) 3)  == (rplaca x 3)
+  (setf (get foo 'bar) 3) == (putprop foo 3 'bar)
+
+the target must be something it has been 'taught' to understand, or it can
+be a macro, in which case setf macro-expands it and takes another look.
+
+The setf macro (and a list of targets it knows about is in
+/usr/lib/lisp/common2.l)
+
+
+
+
+From jkf@UCBKIM  Wed Dec  1 09:13:23 1982
+Date: 1-Dec-82 09:13:03-PST (Wed)
+From: jkf@UCBKIM (John Foderaro)
+Subject: Random Numbers in Franz
+Message-Id: <8211011713.3615@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.255 [11/28/82])
+       id AA03615; 1-Dec-82 09:13:03-PST (Wed)
+Received: from UCBKIM.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
+       id A18406; 1-Dec-82 09:13:23-PST (Wed)
+To: franz-friends@berkeley
+Status: RO
+
+Date: 29-Nov-82 15:56:09-PST (Mon)
+From: alice!sola!mitch
+Subject: Random Numbers in Franz
+To: alice!ucbvax!franz-friends
+
+In general, it is very bad practice to compute a random number between 0
+and n by any expression such as (mod (random) n).  In fact, Franz's
+random function does exactly that, returning the number generated by the
+C function rand(3) modulo n.  This technique uses only the rightmost 
+bits of successive calls to rand, and the righmost n bits of congruential
+sequences (like that returned by rand(3)) have a period of AT MOST 2**n
+(See Knuth vol.2 p. 12).  So using the rightmost two bits will indeed give
+you sequences of at most period 4.  (If your lisp doesn't have this 
+behavior, you're not using the standard rand.)
+
+A better way to do it is to use the high order bits, by dividing the entire
+range up into n pieces and then seeing where you fall.  (This method is
+biased if n is of the same order as the range, though.)
+
+The code I use is:
+
+
+(or (getd '$old-random) (putd '$old-random (getd 'random)))
+
+(defun random n
+  (cond ((eq n 0) ($old-random))
+       ((fix (quotient (boole 1 ($old-random) #o 7777777777)
+                       (quotient #o 7777777777 (arg 1)))))))
+
+               Mitch Marcus
+
+
+
+
+
+From jkf  Thu Dec  2 08:04:37 1982
+Date: 2-Dec-82 08:04:37-PST (Thu)
+From: jkf (John Foderaro)
+Subject: Franz Lisp distribution
+Message-Id: <8211021604.14414@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.255 [11/28/82])
+       id AA14414; 2-Dec-82 08:04:37-PST (Thu)
+To: franz-friends, net-lang-lisp@k
+Status: O
+
+
+       Franz Lisp Distribution
+       
+  This note describes our distribution policy for Franz Lisp.
+
+What is being distributed:
+  We distribute only source code in order to keep the distribution
+  small and relatively Unix independent.   Makefiles are provided to
+  build the entire lisp system from source, even if you don't have
+  a version of lisp running already.  This process takes about 3 cpu
+  hours on a Vax 780.  [This version for the Vax only, a 68000 version
+  is being worked on.  Contact ucbkim.sklower@berkeley or 
+  ucbkim.layer@berkeley]
+
+  The following source is provided:
+    lisp interpreter, 
+    compiler (liszt),
+    cross reference program (lxref),
+    lisp manual,
+    and other utility programs:
+       trace, step, debug, cmu library functions, (and other minor ones),
+       and these packages from the MIT lisp library:
+           defstruct, loop, flavors. 
+           [These programs are provided as a convenience to those who can't
+            access the arpanet and copy them.  There is no documentation for
+            them in the Franz Lisp manual.  The best source of documentation
+            is the Lisp Machine manual (available from MIT, Symbolics
+            or LMI)]
+
+   Regarding Flavors:  there are two implementations of flavors for
+       Franz Lisp, one from MIT (contact person Richard Zippel (rz@mit-mc))
+       and one from the University of Maryland (contact person
+       Liz Allen  (liz.umcp-cs@udel-relay)).  Neither implementation is
+       exactly like flavors on the Lisp Machine (due to differences between
+       Lisp Machine lisp and Franz Lisp), and the implementations differ
+       from each other.    We incorporated the Mit version into the
+       standard distribution because the high bandwidth between here and
+       MIT will insure that it keeps up to date with the current Franz.
+       This is not to imply that it is the better implementation.
+       We haven't had enough experience with flavors to judge.
+       Those seriously interested in Flavors should contact Liz
+       Allen and ask for the Tech Report on the Univ Of Maryland Flavors
+       system.
+
+What is the form of the distribution:
+  The files are packaged in a giant (2.1Mbyte) shell script.  Running this
+shell script through 'sh' will result in a directory tree.  A ReadMe file
+in the current directory will contain instructions on building the lisp
+system.  The shell script is broken into a number of smaller files.
+The current distribution looks like:
+% ls
+total 2092
+ 195 opus38.40.aa       195 opus38.40.ae        195 opus38.40.ai
+ 195 opus38.40.ab       195 opus38.40.af        195 opus38.40.aj
+ 195 opus38.40.ac       195 opus38.40.ag        142 opus38.40.ak
+ 195 opus38.40.ad       195 opus38.40.ah
+
+The '38.40' means Opus 38, minor version 40.  These numbers may be different
+by the time you get your distribution.  In order to extract the lisp
+files from this shell script, you need only type:
+       cat * | sh
+
+
+To get a copy of the distribution:
+  The distribution may be obtained either using FTP from an arpanet site,
+or on a magnetic tape through the U.S Mail.
+
+ Arpanet:
+   The files are stored on the ucb-c70 (NCP) arpanet host in the
+   directory /users/lisp/lispuser.  If you have an account on the ucb-c70,
+   you are free to take FTP a copy of these files.
+   If you do not have an account on the ucb-c70, send me (jkf@berkeley) a
+   message and I will set up a temporary account for you.
+   If you are on a TCP host, write me and we will set up an account on one
+   of our Vax's for you to FTP the files.  Eventually we will have an
+   anonymous login on a TCP machine.
+
+ Mag Tape:
+   In order to get a copy of the distribution mailed to you, send a check to
+ cover our tape copying and mailing costs (fees are listed below).  We will
+ purchase the mag tape and you are free to keep it.  Please do NOT
+ send us a tape.
+
+     Fees:
+               $50     - distribution tape mailed 3rd class
+           add $10     - a copy of the Lisp Manual (we will only
+                         send one copy, you are free to photocopy it)
+           add $7      - send tape via 1st class mail.
+
+            -or-
+               $15     - for just a copy of the Lisp Manual
+
+ The address to send checks to is 
+
+       Keith Sklower
+       EECS/Computer Science Division
+       524 Evans Hall
+       University of California
+       Berkeley, CA  94720
+
+ All checks should be made out to "Regents, University of California."
+ We require pre-payment.  We will not invoice or process purchase orders.
+
+
+
+Disclaimers:
+    This distribution works on the latest versions of Unix running at
+    Berkeley (4.1a).  We can't guarantee that it will work on older
+    versions (although, if you are running 4.1, it is almost certain
+    that it will work, but we have not verified it).
+    VMS users who are using a typical Unix compatibility package will 
+    probably not be able to build a lisp from this distribution unless they
+    know a great deal about VMS and their compatibility package.
+    At least one package (Eunice) supports Franz at this time.
+    
+Redistribution:
+    If you get a copy of the distribution, you are free to give it to
+    other people.  We appreciate being informed of new sites so they
+    can be put on a mailing list (electronic and conventional).  This
+    list is used to announce new releases.  To be put on this list,
+    send U.S. Mail to Keith Sklower (address above) or to 
+    franz-friends-request@berkeley or ucbvax!franz-friends-request
+
+
+
+From jkf  Mon Dec  6 08:50:45 1982
+Date: 6-Dec-82 08:50:45-PST (Mon)
+From: jkf (John Foderaro)
+Subject: opus 38.43
+Message-Id: <8211061650.12951@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA12951; 6-Dec-82 08:50:45-PST (Mon)
+To: local-lisp
+Status: O
+
+  The size of vectors is now recorded in bytes rather than longwords.
+  We've imported a few more commands to deal with fclosures.
+  (symeval-in-fclosure 'fclosure 'symbol)
+  (set-in-fclosure 'fclosure 'symbol 'value)
+
+  (let-fclosed vars function)
+  
+
+
+
+From jkf  Mon Dec 13 10:35:43 1982
+Date: 13-Dec-82 10:35:43-PST (Mon)
+From: jkf (John Foderaro)
+Subject: enhancemants to trace
+Message-Id: <8211131835.12160@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA12160; 13-Dec-82 10:35:43-PST (Mon)
+To: local-lisp
+Status: O
+
+  The function 'retrace' will insure that all functions which should be
+traced are indeed traced.   This will solve the problem of reloading
+a file whose functions are traced.  After you load a file, you can
+type (retrace) and those functions which became untraced during the loading
+process, will be traced again.
+
+  The top-level-print and top-level-read variables will now take effect
+within a trace break.
+
+
+
+
+
+From jkf  Tue Dec 14 12:40:41 1982
+Date: 14-Dec-82 12:40:41-PST (Tue)
+From: jkf (John Foderaro)
+Subject: Re: #!, exec and lisp
+Message-Id: <8211142040.10379@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA10379; 14-Dec-82 12:40:41-PST (Tue)
+To: lime!burdvax!puder
+Cc: franz-friends
+In-Reply-To: Your message of 13-Dec-82 14:03:23-PST (Mon)
+Status: O
+
+   It is easy to make #! do a zapline.   If you have a recent version of
+lisp, just execute:
+
+(defsharp ! (x) (zapline))
+
+(this could be put in your .lisprc, if you don't want to affect other 
+people).    The problem with adding this to Franz by default is that the
+sharpsign macro is shared by a number of lisps and few of them run under
+Unix.   Therefore, few other lisps are going to want #! to be zapline.
+
+
+  Regarding the -f switch:  The -f switch is used to communicate between the
+bootstrap at the beginning of a fasl file and the lisp interpreter.  It
+wasn't meant as a general 'fasl this file' switch for users to make use of.
+The choice of '-f' was bad, it should have been something more unique like
+'-- autorun' so that a user would be unlikely to type it.   We have avoided
+assigning meanings to switches on lisp's command line because we want to give
+each user the opportunity to assign whatever meaning he wants to whatever
+switch he wants.   It isn't difficult to write a program to scan the command
+line.
+
+Re:
+    The (setq searchlist (cvtsearchpathtolist (getenv 'PATH))) would not be
+    necessary, because the exec syscall supplies the full path name, because
+    the shell has already done the path searching on the command name.  The
+    only place that might have to be searched is the current directory.
+
+This isn't true.  (argv 0) is the command that you typed, not the full path
+name to the command.  Only by prepending all the directories in the
+search list can you find the location of the command.
+
+
+                               ---john foderaro
+                               
+
+
+From jkf  Mon Jan 10 15:04:02 1983
+Date: 10-Jan-83 15:04:02-PST (Mon)
+From: jkf (John Foderaro)
+Subject: opus 38.45
+Message-Id: <8300102304.19240@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA19240; 10-Jan-83 15:04:02-PST (Mon)
+To: local-lisp
+Status: O
+
+  showstack will again report correctly for compiled calls if the
+transfer tables are unlinked (status translink nil).
+
+
+
+From jkf  Mon Jan 10 19:46:06 1983
+Date: 10-Jan-83 19:46:06-PST (Mon)
+From: jkf (John Foderaro)
+Subject: opus 38.46
+Message-Id: <8300110346.24831@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA24831; 10-Jan-83 19:46:06-PST (Mon)
+To: local-lisp
+Status: O
+
+ This version incorporates some fixes from mit.  You shouldn't notice
+any differences but if you do, let me know.
+
+
+
+
+
+From jkf  Wed Jan 12 09:03:32 1983
+Date: 12-Jan-83 09:03:32-PST (Wed)
+From: jkf (John Foderaro)
+Subject: opus38.47
+Message-Id: <8300121703.1981@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA01981; 12-Jan-83 09:03:32-PST (Wed)
+To: local-lisp
+Status: O
+
+  The setf macro will now handle all car and cdr forms (i.e. c{ad}+r).
+  Thanks to peter norvig for this.
+
+  There is a new macro called 'defvar'.  It is used to declare special
+variables and optionally to give them an initial value.  It is used
+at top level in a file (outside of defuns).
+
+forms:
+(defvar foo)   ; declares foo to be special
+(defvar bar 3) ; declares bar to be special and when this file is read in
+               ; bar will be given the value 3 if it is unbound.
+An advantage of '(defvar foo)' over '(declare (special foo))' is that if
+a file containing defvars is loaded (or fasl'ed) in during compilation,
+the variables mentioned in the defvar's will be declared special.  The only
+way to have that effect with '(declare (special foo))' is to 'include'
+the file.  
+
+ There is a new macro, 'environment', which can be used at the beginning of
+a file to specify what sort of environment this file needs in order to be
+compiled or run.  For example:
+(environment (compile eval) (files mymacros othermacros)
+            (compile) (syntax maclisp))
+
+says that when compiling or loading into the interpreter, the files
+mymacros and othermacros should be loaded (if they aren't loaded already).
+When compiling, the maclisp syntax should be used.
+The general form of 'environment' is:
+   (environment when1 what1
+               when2 what2
+               ...    ...
+               whenN whatN)
+the when's are a subset of (eval compile load), and the symbols have the
+same meaning as they do in 'eval-when'.
+The what's are either
+       (files file1 file2 ... fileN)
+               insure that the named files are loaded.  To see if fileX
+               is loaded, it looks for a 'version' property under
+               fileX's property list.  Thus to prevent multiple loading,
+               you should put
+               (putprop 'myfile t 'version) at the end of myfile.l
+       (syntax type)
+               type is either maclisp, intlisp, ucilisp, franzlisp
+               This sets the syntax correctly.
+
+There are additional macros to set of standard environments:
+(environment-maclisp)  sets up the maclisp environment.  This is what
+       you would get by using the -m switch to liszt.
+
+(environment-lmlisp)  sets up the lisp machine environment. This is like
+       maclisp but it has additional macros.
+
+       
+It is possible to add when's and what's to the specialized environments,
+e.g.
+ (environment-maclisp (compile eval) (files foo bar))
+
+
+
+  
+
+
+
+From norvig Wed Jan 12 13:12:45 1983
+To: jkf local-lisp
+Subject: defvar
+Status: O
+
+Shouldn't defvar take any number of arguments, like setq?  As it is,
+(defvar a 1 b 2) sets a to 1, but ignores the other arguments.
+
+From fateman Wed Jan 12 13:23:08 1983
+To: jkf local-lisp norvig
+Subject: Re:  defvar
+Status: O
+
+I suspect the extra arguments to defvar are used in other systems for
+storage of documentation strings in appropriate places.  E.g.
+(defvar dozen 12 "initially 12 except in the baker system when it is 13")
+causes some association with defvar and documentation should be put on
+a file.
+
+
+From jkf  Wed Jan 12 14:25:02 1983
+Date: 12-Jan-83 14:25:02-PST (Wed)
+From: jkf (John Foderaro)
+Subject: Re: defvar
+Message-Id: <8300122225.13079@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA13079; 12-Jan-83 14:25:02-PST (Wed)
+To: norvig, local-lisp
+In-Reply-To: Your message of 12 Jan 1983 1311-PST (Wednesday)
+Status: O
+
+ fateman is correct that there is an optional third argument for
+documentation.   We don't want to add multiple arguments because defvar
+it will mean that code we write here can't be transported to
+other lisp which only expect one defvar argument.
+
+
+
+From jkf  Thu Jan 13 09:49:13 1983
+Date: 13-Jan-83 09:49:13-PST (Thu)
+From: jkf (John Foderaro)
+Subject: liszt 8.17
+Message-Id: <8300131749.331@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA00331; 13-Jan-83 09:49:13-PST (Thu)
+To: local-lisp
+Status: O
+
+ The vector reference functions are open coded.  These are
+       vref, vrefi-byte, vrefi-word, vrefi-long
+
+
+
+From G:alpines  Thu Jan 13 20:31:34 1983
+Date: 13 Jan 1983 20:24-PST
+From: alpines@G   (Harry Weeks at Vax-Populi)
+Subject: Franz on 68000's
+Message-Id: <83/01/13 2024.733@Vax-Populi>
+Received: by UCBVAX.BERKELEY.ARPA (3.293 [1/9/83])
+       id AA12970; 13-Jan-83 20:28:37-PST (Thu)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA14908; 13-Jan-83 20:31:34-PST (Thu)
+To: franz@BERKELEY
+Cc: franz-friends@BERKELEY
+Status: O
+
+>Date: 13 Jan 1983 20:01-PST
+From: G.alpines at Berkeley (Harry Weeks at Vax-Populi)
+Subject: Franz on 68000's.
+To: franz-friends-request@Berkeley
+Message-Id: <83/01/13 2001.733@Vax-Populi>
+
+Please put me on your mailing list for information concerning
+implementation of Franz, esp. on 68000's, but I'd like to keep
+informed generally as well.  Thanks.
+
+                                       Harry Weeks
+                                       Bytek
+                                       1730 Solano Avenue
+                                       Berkeley, CA 94707
+                                       
+                                       (415) 527-1157
+
+
+From jkf  Sun Jan 16 21:22:54 1983
+Date: 16-Jan-83 21:22:54-PST (Sun)
+From: jkf (John Foderaro)
+Subject: change to lisptags program
+Message-Id: <8300170522.23656@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA23656; 16-Jan-83 21:22:54-PST (Sun)
+To: local-lisp
+Status: O
+
+ lisptags will now surround the search string with /'s instead of ?'s
+in order to be compatible with ctags.   Both types should work with vi,
+emacs people will probably have to make a minor modification to their
+tags.ml file.
+  My version in ~jkf/elib/tags.ml.
+
+
+
+
+
+From jkf  Tue Jan 18 16:43:23 1983
+Date: 18-Jan-83 16:43:23-PST (Tue)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.48, liszt 8.19
+Message-Id: <8300190043.10935@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA10935; 18-Jan-83 16:43:23-PST (Tue)
+To: local-lisp
+Status: O
+
+  This is a long message so I'll put the most important thing first, in case
+you choose not to read the rest of the message:
+  *** object files generated by liszt 8.19 will not run in any lisp
+  *** older than 38.48.    Object files which were generated by
+  *** liszt's before 8.19 will continue to work in the new lisp.
+
+
+There were two major changes to lisp and liszt:
+ 1) compiled functions will test at runtime to make sure that they
+    are passed the correct number of arguments.
+
+ 2) the lambda list keywords &optional, &rest and &aux are open compiled
+    in an efficient manner.
+
+I'll refresh your memory on what the possible forms are for the & keywords:
+
+  the formal parameter list of a def has this form
+  ( required-args
+    [ &optional optional-arguments ]
+    [ &rest rest-argument ]
+    [ &aux  aux-arguments ])
+
+ as in this example which shows all possible forms:
+
+ (def foo 
+   (lambda (a b &optional c (d 23 d-p) (dd (bar)) &rest e &aux (f 12) g)
+       (compute)))
+
+   
+ the meaning and forms of the various parts of the formal parameter list are:
+
+ required-args: a sequence of n (zero or more) symbols which will be bound
+       to the first n actual arguments.
+
+ optional-args:        a sequence of m (zero or more) symbols which will be
+       bound to the next m actual arguments if they are present, or
+       to default values.
+       the forms of an optional argument are:
+       
+       foo     - bind foo to the argument if it present, otherwise bind it
+                 to nil
+       (foo (expr)) - bind foo to the argument if it is present, otherwise
+               evaluate (expr) and bind foo to the result.
+
+       (foo (expr) foo-p)  - bind foo to the argument if it is present, 
+               otherwise evaluate (expr) and bind foo to the result.
+               Also, bind foo-p to t if the argument is present, otherwise
+               bind foo-p to nil.  foo-p will be treated like an &aux
+               variable (see below) but it should NOT be declared in the
+               &aux list!
+
+  rest-arg : a single symbol which will be bound to a list of the rest of the
+       arguments.  This list is cons'ed up each time the function is called.
+
+  aux-args : these args are just like arguments to let or prog within the
+       function body so this & keyword isn't really necessary (but there
+       are few things in lisp that really are necessary).
+
+       the forms of the aux arg are:
+
+       foo - bind foo to nil
+       (foo (expr))  - evaluate (expr) and bind foo to the result.
+
+
+
+The compiler understands the &keywords but the interpreter does not.  'def'
+will convert a form with &keywords to a lexpr which is almost equivalent.
+The differences are:
+    The interpreted form, being a lexpr, is allowed to use the 'arg'
+       function.  The compiled form, even with optional args,
+       is not a lexpr and thus 'arg' is illegal.
+
+    The order that &aux variables are lambda bound is slightly different
+        between interpreted and compiled code.  As long as default
+       expressions reference no formal parameters after them in the
+       formal parameter list, there should be no problems.
+
+    The interpreted version will not check for the correct number of
+        arguments.
+
+Local functions cannot have &keywords. 
+
+If you have any questions on this, send me mail.  This change should
+only break functions which expect a variable number of argument and
+which don't declare the fact using &optional programs.  There may be,
+of course, implementation errors.  If you notice anything unusual
+please let me know right away.  The old compiler will be
+in /usr/ucb/oliszt for a while.
+
+
+
+       
+    
+       
+
+
+
+From layer  Thu Jan 20 01:55:55 1983
+Date: 20-Jan-83 01:55:55-PST (Thu)
+From: layer (Kevin Layer)
+Subject: liszt 8.20
+Message-Id: <8300200955.17788@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA17788; 20-Jan-83 01:55:55-PST (Thu)
+To: local-lisp
+Phone: (415) 652-2405
+Status: O
+
+    There are now three new command line features for liszt:
+
+    1. -E <s-expr>, where <s-expr> will be evaluated before compilation
+       starts.  For example, the setting of constants can be done in this way:
+
+          liszt -E '(setq foobar "***foobar-string***")' foobar.l
+
+       and in the file being compiled, foobar is accessed as '#.foobar.
+
+    2. -I <include-file>, where <include-file> will be loaded (via load)
+       before compilation starts.
+
+    3. A combination of the -S and -o switches will set the .s file, as in:
+
+        liszt -S -o foo.vax.s foo.l
+
+      where previously, the -S determined the name of the .s file (foo.s in
+      the above example).
+      
+
+
+From jkf  Thu Jan 20 19:42:38 1983
+Date: 20-Jan-83 19:42:38-PST (Thu)
+From: jkf (John Foderaro)
+Subject: some mods to liszt 8.20
+Message-Id: <8300210342.7334@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA07334; 20-Jan-83 19:42:38-PST (Thu)
+To: local-lisp
+Status: O
+
+ the -E and -I flags are now -e and -i
+ there may be more than one -i flag given on the command line.
+
+
+From fateman Thu Jan 20 20:20:31 1983
+To: local-lisp
+Subject: fame, if not fortune
+Status: RO
+
+In the latest Scientific American, Feb. 1983, Hofstader's column
+is the first of several on the programming language "lisp".  He
+mentions the particular dialect he is using .... Franz !
+
+From wilensky  Thu Jan 20 20:57:27 1983
+Date: 20-Jan-83 20:57:27-PST (Thu)
+From: wilensky (Robert Wilensky)
+Subject: Re: fame, if not fortune
+Message-Id: <8300210457.8824@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA08824; 20-Jan-83 20:57:27-PST (Thu)
+To: fateman, local-lisp
+In-Reply-To: Your message of 20 Jan 1983 2019-PST (Thursday)
+Status: RO
+
+
+On the other hand, being referenced by Hofstader is a dubious honor.
+
+
+From UCBKIM:jkf  Fri Jan 21 08:15:04 1983
+Date: 21-Jan-83 08:11:01-PST (Fri)
+From: UCBKIM:jkf (John Foderaro)
+Subject: test message, ignore
+Message-Id: <8300211611.18650@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA18650; 21-Jan-83 08:11:01-PST (Fri)
+Received: from UCBKIM.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA24887; 21 Jan 83 08:09:27 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA18766; 21-Jan-83 08:15:04-PST (Fri)
+To: franz-friends@BERKELEY
+Status: O
+
+ This will give our mailer a chance to tell me how many of our franz friends
+are no longer reachable.
+
+
+
+From JTSCHUDY@USC-ISIE  Sat Jan 22 16:42:19 1983
+Date: 22 Jan 1983 1634-PST
+From: JTSCHUDY@USC-ISIE
+Subject: MAILINGLIST ADDITION
+Message-Id: <8300230037.1747@UCBVAX.BERKELEY.ARPA>
+Received: from USC-ISIE by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA01747; 22 Jan 83 16:37:17 PST (Sat)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA18903; 22-Jan-83 16:42:19-PST (Sat)
+To: franz-friends@BERKELEY
+Status: O
+
+Hi!  My name is Jim.  I am presently attending the Naval Post Graduate
+School in Monterey California.  I am in the Air Force  enrolled  in  a
+DOD  sponsored  graduate  degree in Command Control and Communications
+Systems Technology.
+
+i  would  like  to  be  added to your mailing list.  My net address is
+JTSCHUDY at ISIE.
+
+Thanks - Jim.
+-------
+
+
+From jkf  Sat Jan 22 17:38:41 1983
+Date: 22-Jan-83 17:38:41-PST (Sat)
+From: jkf (John Foderaro)
+Subject: opus 38.49
+Message-Id: <8300230138.20020@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA20020; 22-Jan-83 17:38:41-PST (Sat)
+To: local-lisp
+Status: O
+
+  A longstanding bug in the determination of the number of free dtpr objects
+has been found and fixed.  The effect of this bug was that the function
+which is responsible for allocating more memory pages didn't allocate
+enough dtpr pages because it thought that there were a large number of
+cells free.
+
+
+
+From MCLINDEN@RUTGERS  Mon Jan 24 10:33:14 1983
+Date: 24 Jan 1983 1324-EST
+From: Sean McLinden  <MCLINDEN@RUTGERS>
+Subject: Franz Lisp and floating point accelerator
+Message-Id: <8300241825.19602@UCBVAX.BERKELEY.ARPA>
+Received: from RUTGERS by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA19602; 24 Jan 83 10:25:06 PST (Mon)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA27143; 24-Jan-83 10:33:14-PST (Mon)
+To: franz-friends@UCBVAX
+Status: O
+
+
+  Has anyone determined if a floating point accelerator speeds up
+ Vax Franz Lisp jobs in any significant fashion?
+
+  Pointers would be appreciated.
+
+  Sean McLinden
+  Decision Systems Lab
+-------
+
+From mike@rand-unix  Mon Jan 24 18:47:03 1983
+Date: Monday, 24 Jan 1983 15:34-PST
+From: mike@RAND-UNIX
+Subject: emacs interface to franz?
+Message-Id: <8300250008.58@UCBVAX.BERKELEY.ARPA>
+Received: from rand-unix by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA00058; 24 Jan 83 16:08:36 PST (Mon)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA00921; 24-Jan-83 18:47:03-PST (Mon)
+To: franz-friends@BERKELEY
+Status: O
+
+
+Does anyone have a snazzy interface to emacs for franz?  
+
+Thanks,
+  Michael
+
+
+From @udel-relay.ARPA,@UDel-Relay:Tim@UPenn.UPenn  Tue Jan 25 16:29:19 1983
+Date: 25 Jan 1983  9:58-EST
+From: Tim Finin <Tim.UPenn@UDel-Relay>
+Subject: emacs interface to franz?
+Message-Id: <8300260022.29320@UCBVAX.BERKELEY.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA29320; 25 Jan 83 16:22:57 PST (Tue)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA01561; 25-Jan-83 16:29:19-PST (Tue)
+Return-Path: <Tim@UPenn.UPenn@UDel-Relay>
+To: mike@Rand-Unix
+Cc: franz-friends@BERKELEY
+Via:  UPenn; 25 Jan 83 19:21-EST
+Status: O
+
+
+We have a simple interface from Franz to Emacs, but I much prefer to go the
+other way, i.e. run Franz as a inferior job under Emacs.  I believe there
+are several Emacs packages which allow one to run inferior jobs in an Emacs
+window (I have my own which is, unfortunately totally undocumented). Some of
+the benefits of this set up include:
+
+    - one has all of the text editing functions available in Emacs
+    - one has many lisp-based editing functions available in Emacs
+      (thru mock-lisp packages like electriclisp)
+    - one has a history of the session in the editing buffer
+    - one has an environment which supports multiple concurrent
+      processes running in seperate windows.
+    - it is very easy to experiment with new interface features such as
+      symbol completion and re-evaluation of previously issued commands
+    
+Tim
+    
+
+From CARR@UTAH-20  Fri Jan 28 08:19:08 1983
+Date: 28 Jan 1983 0912-MST
+From: Harold Carr <CARR@UTAH-20>
+Subject: franz distribution
+Message-Id: <8300281615.20646@UCBVAX.BERKELEY.ARPA>
+Received: from UTAH-20 by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA20646; 28 Jan 83 08:15:18 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA16991; 28-Jan-83 08:19:08-PST (Fri)
+To: franz-friends@UCBVAX
+Status: O
+
+What is the distribution policy?
+
+I work for a company that has opus 36 and is now currently running opus 37.
+Here at the University of Utah we are running opus 38.04. Is it OK to
+make a tape of the University's 38.04 to bring my company more up to
+date? Do I have to make it more formal by signing a transfer agreement
+or by obtaining the release directly from Berkeley?
+
+                              Thanks in advance,
+                                 Harold Carr
+                                CARR@UTAH-20
+-------
+
+From UCBKIM:jkf  Fri Jan 28 15:09:32 1983
+Date: 28-Jan-83 08:34:33-PST (Fri)
+From: UCBKIM:jkf
+Subject: Re: franz distribution
+Message-Id: <8300281634.17319@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA17319; 28-Jan-83 08:34:33-PST (Fri)
+Received: from UCBKIM.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA02275; 28 Jan 83 14:58:37 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA00402; 28-Jan-83 15:09:32-PST (Fri)
+To: CARR@UTAH-20
+Cc: franz-friends@UCBVAX
+In-Reply-To: Your message of 28 Jan 1983 0912-MST
+Status: O
+
+  Here is our current distribution policy.  This differs a bit from
+the one sent out a month ago [in particular, we now have anonymous ftp]
+
+                                   -[Fri Jan 28 08:31:45 1983 by jkf]-
+       Franz Lisp Distribution
+       
+  This note describes our distribution policy for Franz Lisp.
+
+What is being distributed:
+  We distribute only source code in order to keep the distribution
+  small and relatively Unix independent.   Makefiles are provided to
+  build the entire lisp system from source, even if you don't have
+  a version of lisp running already.  This process takes about 3 cpu
+  hours on a Vax 780.  [This version for the Vax only, a 68000 version
+  is being worked on.  Contact ucbkim.sklower@berkeley or 
+  ucbkim.layer@berkeley]
+
+  The following source is provided:
+    lisp interpreter, 
+    compiler (liszt),
+    cross reference program (lxref),
+    lisp manual,
+    and other utility programs:
+       trace, step, debug, cmu library functions, (and other minor ones),
+       and these packages from the MIT lisp library:
+           defstruct, loop. 
+           [These programs are provided as a convenience to those who can't
+            access the arpanet and copy them.  There is no documentation for
+            them in the Franz Lisp manual.  The best source of documentation
+            is the Lisp Machine manual (available from MIT, Symbolics
+            or LMI)]
+
+   Regarding Flavors:  there are two implementations of flavors for
+       Franz Lisp, one from MIT (contact person Richard Zippel (rz@mit-mc))
+       and one from the University of Maryland (contact person
+       Liz Allen  (liz.umcp-cs@udel-relay)).  Neither implementation is
+       exactly like flavors on the Lisp Machine (due to differences between
+       Lisp Machine lisp and Franz Lisp), and the implementations differ
+       from each other.    The MIT version cannot be distributed by 
+       us (yet) due to licensing problems.   If you have a Lisp Machine
+       Source license from Symbolics, you should be able to get a copy
+       from MIT.
+       For a Tech Report on Maryland flavors, write to Liz Allen.
+
+What is the form of the distribution:
+  The files are packaged in a giant (2.1Mbyte) shell script.  Running this
+shell script through 'sh' will result in a directory tree.  A ReadMe file
+in the current directory will contain instructions on building the lisp
+system.  The shell script is broken into a number of smaller files.
+The current distribution looks like:
+
+total 2089
+ 489 -rw-r--r--  1 jkf        500003 Jan 26 11:33 opus38.50.aa
+ 489 -rw-r--r--  1 jkf        500002 Jan 26 11:35 opus38.50.ab
+ 489 -rw-r--r--  1 jkf        500047 Jan 26 11:37 opus38.50.ac
+ 489 -rw-r--r--  1 jkf        500007 Jan 26 11:38 opus38.50.ad
+ 133 -rw-r--r--  1 jkf        136038 Jan 26 11:39 opus38.50.ae
+
+The '38.50' means Opus 38, minor version 50.  These numbers may be different
+by the time you get your distribution.  In order to extract the lisp
+files from this shell script, you need only type:
+       cat * | sh
+
+
+To get a copy of the distribution:
+  The distribution may be obtained either using FTP from an arpanet site,
+or on a magnetic tape through the U.S Mail.
+
+ Arpanet:
+   The files are stored on the arpanet host 'ucb-vax' [ if you have an out
+   of date host table, it may be called 'ucb-monet' or 'ucb-ingres'. Its
+   internet number is 10.2.0.78].
+   You can login as 'anonymous'.   Use your name as the password.
+   The files are in the subdirectory pub/lisp.
+   
+   For those who have accounts on ucb-vax, the full path is ~ftp/pub/lisp.
+
+ Mag Tape:
+   In order to get a copy of the distribution mailed to you, send a check to
+ cover our tape copying and mailing costs (fees are listed below).  We will
+ purchase the mag tape and you are free to keep it.  Please do NOT
+ send us a tape.
+
+     Fees:
+               $50     - distribution tape mailed 3rd class
+           add $10     - a copy of the Lisp Manual (we will only
+                         send one copy, you are free to photocopy it)
+           add $7      - send tape via 1st class mail.
+
+            -or-
+               $15     - for just a copy of the Lisp Manual
+
+ The address to send checks to is 
+
+       Keith Sklower
+       EECS/Computer Science Division
+       524 Evans Hall
+       University of California
+       Berkeley, CA  94720
+
+ All checks should be made out to "Regents, University of California."
+ We require pre-payment.  We will not invoice or process purchase orders.
+
+
+
+Disclaimers:
+    This distribution works on the latest versions of Unix running at
+    Berkeley (4.1a).  We can't guarantee that it will work on older
+    versions (although, if you are running 4.1, it is almost certain
+    that it will work, but we have not verified it).
+    VMS users who are using a typical Unix compatibility package will 
+    probably not be able to build a lisp from this distribution unless they
+    know a great deal about VMS and their compatibility package.
+    At least one package (Eunice) supports Franz at this time.
+    
+Redistribution:
+    If you get a copy of the distribution, you are free to give it to
+    other people.  We appreciate being informed of new sites so they
+    can be put on a mailing list (electronic and conventional).  This
+    list is used to announce new releases.  To be put on this list,
+    send U.S. Mail to Keith Sklower (address above) or to 
+    franz-friends-request@berkeley or ucbvax!franz-friends-request
+
+
+
+From Kim:fateman  Sun Jan 30 02:12:28 1983
+Date: 28 Jan 83 08:32:08 PST (Fri)
+From: Kim:fateman (Richard Fateman)
+Subject: Re:  franz distribution
+Message-Id: <8300281631.21039@UCBVAX.BERKELEY.ARPA>
+Received: by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA21039; 28 Jan 83 08:31:58 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA10132; 30-Jan-83 02:12:28-PST (Sun)
+To: CARR@UTAH-20
+Cc: franz-friends@ucbvax
+Status: O
+
+Our policy is that you may move copies of Franz elsewhere
+without notifying us.  We continue to be interested in sharing anything
+you or your company wish to provide us, in suggestions, programs, etc.
+
+
+From UCBCAD:pettengi  Sun Jan 30 02:33:52 1983
+Date: 28-Jan-83 10:54:51-PST (Fri)
+From: UCBCAD:pettengi (Rob Pettengill)
+Subject: emacs interface to franz?
+Message-Id: <8300281854.26156@UCBCAD.BERKELEY.ARPA>
+Received: by UCBCAD.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA26156; 28-Jan-83 10:54:51-PST (Fri)
+Received: from UCBCAD.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA00374; 28 Jan 83 12:53:44 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA10578; 30-Jan-83 02:33:52-PST (Sun)
+To: mike@rand-unix, franz-friends@ucbvax
+Cc: pettengi@UCBCAD
+Status: O
+
+       While I was at TI I used a very nice interface that let one start up
+a Franz lisp inside an Emacs window.  It came from SRI when we got Eunice to run
+under our VMS.  Try Kashtan@SRI-AI.
+
+Rob Pettengill
+E-Systems, Dallas, Tx.
+
+From UCBKIM:jkf  Sun Jan 30 02:44:27 1983
+Date: 28-Jan-83 08:34:33-PST (Fri)
+From: UCBKIM:jkf (John Foderaro)
+Subject: Re: franz distribution
+Message-Id: <8300281634.17319@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA17319; 28-Jan-83 08:34:33-PST (Fri)
+Received: from UCBKIM.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA02275; 28 Jan 83 14:58:37 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA10772; 30-Jan-83 02:44:27-PST (Sun)
+To: CARR@UTAH-20
+Cc: franz-friends@UCBVAX
+In-Reply-To: Your message of 28 Jan 1983 0912-MST
+Status: RO
+
+  Here is our current distribution policy.  This differs a bit from
+the one sent out a month ago [in particular, we now have anonymous ftp]
+
+                                   -[Fri Jan 28 08:31:45 1983 by jkf]-
+       Franz Lisp Distribution
+       
+  This note describes our distribution policy for Franz Lisp.
+
+What is being distributed:
+  We distribute only source code in order to keep the distribution
+  small and relatively Unix independent.   Makefiles are provided to
+  build the entire lisp system from source, even if you don't have
+  a version of lisp running already.  This process takes about 3 cpu
+  hours on a Vax 780.  [This version for the Vax only, a 68000 version
+  is being worked on.  Contact ucbkim.sklower@berkeley or 
+  ucbkim.layer@berkeley]
+
+  The following source is provided:
+    lisp interpreter, 
+    compiler (liszt),
+    cross reference program (lxref),
+    lisp manual,
+    and other utility programs:
+       trace, step, debug, cmu library functions, (and other minor ones),
+       and these packages from the MIT lisp library:
+           defstruct, loop. 
+           [These programs are provided as a convenience to those who can't
+            access the arpanet and copy them.  There is no documentation for
+            them in the Franz Lisp manual.  The best source of documentation
+            is the Lisp Machine manual (available from MIT, Symbolics
+            or LMI)]
+
+   Regarding Flavors:  there are two implementations of flavors for
+       Franz Lisp, one from MIT (contact person Richard Zippel (rz@mit-mc))
+       and one from the University of Maryland (contact person
+       Liz Allen  (liz.umcp-cs@udel-relay)).  Neither implementation is
+       exactly like flavors on the Lisp Machine (due to differences between
+       Lisp Machine lisp and Franz Lisp), and the implementations differ
+       from each other.    The MIT version cannot be distributed by 
+       us (yet) due to licensing problems.   If you have a Lisp Machine
+       Source license from Symbolics, you should be able to get a copy
+       from MIT.
+       For a Tech Report on Maryland flavors, write to Liz Allen.
+
+What is the form of the distribution:
+  The files are packaged in a giant (2.1Mbyte) shell script.  Running this
+shell script through 'sh' will result in a directory tree.  A ReadMe file
+in the current directory will contain instructions on building the lisp
+system.  The shell script is broken into a number of smaller files.
+The current distribution looks like:
+
+total 2089
+ 489 -rw-r--r--  1 jkf        500003 Jan 26 11:33 opus38.50.aa
+ 489 -rw-r--r--  1 jkf        500002 Jan 26 11:35 opus38.50.ab
+ 489 -rw-r--r--  1 jkf        500047 Jan 26 11:37 opus38.50.ac
+ 489 -rw-r--r--  1 jkf        500007 Jan 26 11:38 opus38.50.ad
+ 133 -rw-r--r--  1 jkf        136038 Jan 26 11:39 opus38.50.ae
+
+The '38.50' means Opus 38, minor version 50.  These numbers may be different
+by the time you get your distribution.  In order to extract the lisp
+files from this shell script, you need only type:
+       cat * | sh
+
+
+To get a copy of the distribution:
+  The distribution may be obtained either using FTP from an arpanet site,
+or on a magnetic tape through the U.S Mail.
+
+ Arpanet:
+   The files are stored on the arpanet host 'ucb-vax' [ if you have an out
+   of date host table, it may be called 'ucb-monet' or 'ucb-ingres'. Its
+   internet number is 10.2.0.78].
+   You can login as 'anonymous'.   Use your name as the password.
+   The files are in the subdirectory pub/lisp.
+   
+   For those who have accounts on ucb-vax, the full path is ~ftp/pub/lisp.
+
+ Mag Tape:
+   In order to get a copy of the distribution mailed to you, send a check to
+ cover our tape copying and mailing costs (fees are listed below).  We will
+ purchase the mag tape and you are free to keep it.  Please do NOT
+ send us a tape.
+
+     Fees:
+               $50     - distribution tape mailed 3rd class
+           add $10     - a copy of the Lisp Manual (we will only
+                         send one copy, you are free to photocopy it)
+           add $7      - send tape via 1st class mail.
+
+            -or-
+               $15     - for just a copy of the Lisp Manual
+
+ The address to send checks to is 
+
+       Keith Sklower
+       EECS/Computer Science Division
+       524 Evans Hall
+       University of California
+       Berkeley, CA  94720
+
+ All checks should be made out to "Regents, University of California."
+ We require pre-payment.  We will not invoice or process purchase orders.
+
+
+
+Disclaimers:
+    This distribution works on the latest versions of Unix running at
+    Berkeley (4.1a).  We can't guarantee that it will work on older
+    versions (although, if you are running 4.1, it is almost certain
+    that it will work, but we have not verified it).
+    VMS users who are using a typical Unix compatibility package will 
+    probably not be able to build a lisp from this distribution unless they
+    know a great deal about VMS and their compatibility package.
+    At least one package (Eunice) supports Franz at this time.
+    
+Redistribution:
+    If you get a copy of the distribution, you are free to give it to
+    other people.  We appreciate being informed of new sites so they
+    can be put on a mailing list (electronic and conventional).  This
+    list is used to announce new releases.  To be put on this list,
+    send U.S. Mail to Keith Sklower (address above) or to 
+    franz-friends-request@berkeley or ucbvax!franz-friends-request
+
+
+
+From Kim:fateman  Mon Jan 31 19:30:20 1983
+Date: 28 Jan 83 08:32:08 PST (Fri)
+From: Kim:fateman (Richard Fateman)
+Subject: Re:  franz distribution
+Message-Id: <8300281631.21039@UCBVAX.BERKELEY.ARPA>
+Received: by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA21039; 28 Jan 83 08:31:58 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA03502; 31-Jan-83 19:30:20-PST (Mon)
+To: CARR@UTAH-20
+Cc: franz-friends@ucbvax
+Status: O
+
+Our policy is that you may move copies of Franz elsewhere
+without notifying us.  We continue to be interested in sharing anything
+you or your company wish to provide us, in suggestions, programs, etc.
+
+
+From UCBCAD:pettengi  Mon Jan 31 19:55:02 1983
+Date: 28-Jan-83 10:54:51-PST (Fri)
+From: UCBCAD:pettengi (Rob Pettengill)
+Subject: emacs interface to franz?
+Message-Id: <8300281854.26156@UCBCAD.BERKELEY.ARPA>
+Received: by UCBCAD.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA26156; 28-Jan-83 10:54:51-PST (Fri)
+Received: from UCBCAD.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA00374; 28 Jan 83 12:53:44 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA03987; 31-Jan-83 19:55:02-PST (Mon)
+To: mike@rand-unix, franz-friends@ucbvax
+Cc: pettengi@UCBCAD
+Status: O
+
+       While I was at TI I used a very nice interface that let one start up
+a Franz lisp inside an Emacs window.  It came from SRI when we got Eunice to run
+under our VMS.  Try Kashtan@SRI-AI.
+
+Rob Pettengill
+E-Systems, Dallas, Tx.
+
+From Kim:fateman  Mon Jan 31 21:34:44 1983
+Date: 28 Jan 83 08:32:08 PST (Fri)
+From: Kim:fateman (Richard Fateman)
+Subject: Re:  franz distribution
+Message-Id: <8300281631.21039@UCBVAX.BERKELEY.ARPA>
+Received: by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA21039; 28 Jan 83 08:31:58 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA00642; 31-Jan-83 21:34:44-PST (Mon)
+To: CARR@UTAH-20
+Cc: franz-friends@ucbvax
+Status: RO
+
+Our policy is that you may move copies of Franz elsewhere
+without notifying us.  We continue to be interested in sharing anything
+you or your company wish to provide us, in suggestions, programs, etc.
+
+
+From UCBCAD:pettengi  Mon Jan 31 22:12:30 1983
+Date: 28-Jan-83 10:54:51-PST (Fri)
+From: UCBCAD:pettengi (Rob Pettengill)
+Subject: emacs interface to franz?
+Message-Id: <8300281854.26156@UCBCAD.BERKELEY.ARPA>
+Received: by UCBCAD.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA26156; 28-Jan-83 10:54:51-PST (Fri)
+Received: from UCBCAD.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA00374; 28 Jan 83 12:53:44 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA01266; 31-Jan-83 22:12:30-PST (Mon)
+To: mike@rand-unix, franz-friends@ucbvax
+Cc: pettengi@UCBCAD
+Status: O
+
+       While I was at TI I used a very nice interface that let one start up
+a Franz lisp inside an Emacs window.  It came from SRI when we got Eunice to run
+under our VMS.  Try Kashtan@SRI-AI.
+
+Rob Pettengill
+E-Systems, Dallas, Tx.
+
+From UCBKIM:jkf  Tue Feb  1 10:35:21 1983
+Date: 1-Feb-83 10:32:24-PST (Tue)
+From: UCBKIM:jkf (John Foderaro)
+Subject: multiple messages
+Message-Id: <8301011832.599@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA00599; 1-Feb-83 10:32:24-PST (Tue)
+Received: from UCBKIM.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA00473; 1 Feb 83 10:32:35 PST (Tue)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA00644; 1-Feb-83 10:35:21-PST (Tue)
+To: franz-friends@ucbvax
+Status: RO
+
+  I'm sorry for the multiple messages.  The franz-friends mailing list is
+huge and the machine which does the mailing is crashing often.  Our local
+mail wizard informs me that if it crashes while in the middle of sending
+mail it will not have a record of who it sent to before the crash.
+  I hope you don't get too many copies of this message.
+  
+  
+
+
+
+From mike@rand-unix  Wed Feb  2 05:33:01 1983
+Date: Tuesday,  1 Feb 1983 15:06-PST
+From: mike@RAND-UNIX
+Subject: response to "emacs interface to franz?"
+Message-Id: <8301021325.221@UCBVAX.BERKELEY.ARPA>
+Received: from rand-unix by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA00221; 2 Feb 83 05:25:50 PST (Wed)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA24463; 2-Feb-83 05:33:01-PST (Wed)
+To: franz-friends@BERKELEY
+Cc: mike@RAND-UNIX
+Status: RO
+
+
+Here are the responses that I received to my question "What's out
+there for emacs?"  
+
+
+------- Forwarded Messages
+
+Received: From SU-SCORE by RAND-UNIX at Mon Jan 24 23:41:37 1983
+Date: Mon 24 Jan 83 22:43:01-PST
+From: Jay Lark <CSD.LARK@SU-SCORE.ARPA>
+Subject: Re: emacs interface to franz?
+To: mike@RAND-UNIX.ARPA
+In-Reply-To: Your message of Mon 24 Jan 83 18:49:21-PST
+
+I'm sure you've probably received several messages similar to this one,
+but just in case...
+
+There exists the capability in Unix Emacs to run a process in its own
+buffer.  Typein can be directed to the process, and output is just sent
+right to the buffer.  This is an excellent way of running Lisp, because 
+you get all of the nice Emacs features (paren balancing, local sexpr
+editing) at essentially no cost.  I have been largely unsuccessful with
+trying to run Emacs under Lisp.
+
+The process package is part of the standard Unix Emacs distribution.
+
+Jay Lark
+-------
+
+
+------- Message 2
+
+Received: From UTAH-CS by RAND-UNIX at Tue Jan 25 07:01:36 1983
+Date: 25 Jan 1983 7:20-MST
+From: Russ Fish <utah-gr!fish@UTAH-CS> (host 10.0.0.4)
+Subject: Re: emacs interface to franz?
+To: mike@RAND-UNIX
+Cc: utah-gr!galway@UTAH-CS
+In-Reply-To: mike's message of Monday, 24 Jan 1983 15:34-PST
+
+We have been running our PSL (Portable Standard Lisp) in gemacs
+(Gosling's emacs) windows for some time.  I suspect it would be a minor
+hack to convert it to Franz, but haven't done it and am not a Franz
+user.  I could mail you our .ml code if you wanted to undertake
+converting it to Franz (or just using it for inspiration and hacking
+your own) and distributing it to Franz folks.
+
+It works like this:  The lisp process is associated with a gemacs
+buffer/window.  In that window you can carry on a normal line-by-line
+conversation, if you wish.  <CR> sends the current line, (back to mark,
+which is left after the prompt) into the lisp.  We mostly use the PSL
+in Rlisp syntax, which is algol-like, but this part of the code is just
+a wrapping for the new-shell function in process.ml with appropriate
+editting syntax set, so you could do the same with no work for any
+Lisp.
+
+You can send an expression, fn def, etc. from any other lisp-mode
+window with a single keypress.  Echoing as input in the dialog window
+is inhibited if a prefix arg is provided, so you don't have to look at
+long exprs or fn defs again, just the lisp response.  
+
+Sending multiple line exprs in response to a single prompt depends on
+the fact that PSL numbers the prompts for history, like the c-shell.  A
+gemacs mlisp output filter process monitors the output for toploop
+prompts and feeds another line of input if the same prompt number comes
+back, instead of printing the prompt.
+
+The result is pretty classy.  You get the full many-window gemacs
+editing environment with tags, etc. for random-access navigation and
+just send chunks of code as you change them.  The extreme of usage is
+"menu" like windows which contain debugging code in clusters rather
+than sequences.  You select exprs with the cursor and send them in any
+order.
+
+We also provide key fns for the common case of sending single lines to
+the toploop or single-character commands to the break-loop without
+editting them into a buffer.
+
+Best respond directly to me, since I am not on Franz-Friends.
+
+-Russ Fish  (Fish@Utah-20, utah-cs!fish)
+
+
+
+------- Message 3
+
+Received: From UDEL-RELAY by RAND-UNIX at Tue Jan 25 18:18:55 1983
+Return-Path: <israel.umcp-cs@UDel-Relay>
+Date:     25 Jan 83 15:13:51 EST  (Tue)
+From: Bruce Israel <israel.umcp-cs@UDel-Relay>
+Subject:  Re:  emacs interface to franz?
+To: mike@RAND-UNIX
+In-Reply-To: Message of Monday, 24 Jan 1983 15:34-PST from mike@RAND-UNIX
+               <8300250008.58@UCBVAX.BERKELEY.ARPA>
+Via:  UMCP-CS; 25 Jan 83 20:45-EST
+
+We have a few franz<->emacs interfaces, but I'm not sure what you mean.
+One is the process.ml package that comes with gosling's emacs (the emacs
+that I assume you are talking about).  With this package, you can run
+franz inside a window from within emacs and have the facilities of an
+editor along with lisp.  The other thing we have is a local Franz
+package called the load1 package.  This package was written for
+compiling flavors (like in the lisp machine; another local package)
+and has a function called vi.  (vi 'lisp-function) will call the
+editor (from the environment variable VISUAL, /usr/ucb/vi is default) on the
+file which contains the definition of the lisp function, positioning
+the editor at the point in the file where the function is defined.  Upon
+exiting the editor, it asks you if you want to reload the modified file.
+To edit a function from a file this way, the file must have been load1'ed
+previously so that the info on where the function is stored and what type
+it is will have been saved.  Load1 will distinguish between different
+types of functions, ie. defflavors, defmethods, defmacros, defuns etc.
+and will search for the correct definition in the file.  Is this what
+you mean?  If you like I can send you the four or five files necessary.
+- Bruce
+
+
+------- Message 4
+
+Received: From CMU-CS-VLSI by RAND-UNIX at Thu Jan 27 06:53:41 1983
+Date: 27 Jan 1983 09:44-EST
+From: Carl.Ebeling@CMU-CS-VLSI
+Subject: Re: emacs interface to franz?
+To: mike@RAND-UNIX
+Message-Id: <412526661/ce@CMU-CS-VLSI>
+In-Reply-To: mike@RAND-UNIX's bboard message of 27-Jan-83 04:14    
+
+I have an electric lisp package and process package for emacs.  It
+includes 'zap-function-to-lisp' among other things.  It is for
+Gosling's emacs and uses the subprocess facility.  I can mail them to
+you if you like.
+       Carl
+
+
+------- End of Forwarded Messages
+
+From UCBKIM:jkf  Wed Feb  2 08:19:19 1983
+Date: 2-Feb-83 08:14:21-PST (Wed)
+From: UCBKIM:jkf (John Foderaro)
+Subject: multiple messages fixed?
+Message-Id: <8301021614.25937@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA25937; 2-Feb-83 08:14:21-PST (Wed)
+Received: from UCBKIM.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA00384; 2 Feb 83 08:10:26 PST (Wed)
+Received: by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA00477; 2 Feb 83 08:14:35 PST (Wed)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA26020; 2-Feb-83 08:19:19-PST (Wed)
+To: franz-friends@ucbvax
+Status: RO
+
+ I've broken the franz-friends mailing list over two machines.  I hope that
+this will fix the problem of mail to franz-friends crashing ucbvax every
+thirty minutes.   If you get multiple copies of this message, please do not
+tell me about it, I will already know.
+
+
+
+
+From jkf  Thu Feb 10 21:45:17 1983
+Date: 10-Feb-83 21:45:17-PST (Thu)
+From: jkf (John Foderaro)
+Subject: liszt 8.21
+Message-Id: <8301110545.16021@UCBKIM.BERKELEY.ARPA>
+Received: by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA16021; 10-Feb-83 21:45:17-PST (Thu)
+To: local-lisp
+Status: O
+
+  more functions open coded: vsize, vsize-byte, vsize-word,
+       vectorp, vectorip
+       
+
+
+From PSI.KROHNFELDT@UTAH-20  Fri Feb 11 15:09:11 1983
+Date: 11 Feb 1983 1601-MST
+From: Jed Krohnfeldt <PSI.KROHNFELDT@UTAH-20>
+Subject: cfasl
+Message-Id: <8301112302.7475@UCBVAX.BERKELEY.ARPA>
+Received: from UTAH-20 by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA07475; 11 Feb 83 15:02:05 PST (Fri)
+Received: by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA07565; 11 Feb 83 15:06:37 PST (Fri)
+Received: from UCBVAX.BERKELEY.ARPA by UCBKIM.BERKELEY.ARPA (3.256 [12/5/82])
+       id AA14422; 11-Feb-83 15:09:11-PST (Fri)
+To: Franz-friends@UCBVAX
+Status: O
+
+I am having trouble using cfasl in franz 38.04.  I keep getting the
+message "ld: /usr/ucb/lisp : no namelist".  Can anyone decipher this
+for me?  Thanks...
+-------
+
+From apm@cmu-ri-isl  Mon Feb 14 07:31:54 1983
+Date: 14 Feb 1983 10:24:21-EST
+From: Andrew.Mendler@CMU-RI-ISL
+Subject: franz lisp under5 vms 3.0
+Message-Id: <8302141531.27879@UCBVAX.ARPA>
+Received: from CMU-RI-ISL by UCBVAX.ARPA (3.310/3.3)
+       id AA27879; 14 Feb 83 07:31:54 PST (Mon)
+Received: by UCBKIM.ARPA (3.310/3.3)
+       id AA01172; 14 Feb 83 15:50:41 PST (Mon)
+To: franz-friends@BERKELEY.ARPA
+Status: O
+
+Does anyone have a copy of Franz Lisp and the compiler that works under
+VMS version 3.0?  
+
+From @udel-relay:tim.unc@UDel-Relay  Mon Feb 14 02:52:18 1983
+Date:     13 Feb 83 14:34:48 EST  (Sun)
+From: Tim Maroney <tim.unc@UDel-Relay>
+Subject:  cfasl: no namelist
+Return-Path: <tim.unc@UDel-Relay>
+Message-Id: <8302141052.25792@UCBVAX.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.ARPA (3.310/3.3)
+       id AA25792; 14 Feb 83 02:52:18 PST (Mon)
+Received: by UCBKIM.ARPA (3.310/3.3)
+       id AA02234; 14 Feb 83 16:18:42 PST (Mon)
+To: franz-friends@BERKELEY.ARPA
+Via:  UNC; 14 Feb 83 5:43-EST
+Status: O
+
+I don't seem to be able to write Jed Krohnfeldt, and this
+answer is probably of general interest anyway. The message
+"ld: no namelist" means that some well-meaning system admin
+has stripped the lisp executable file to save space;
+unfortunately, this makes the dynamic loading used by cfasl
+impossible. Lisp will have to be recompiled (groan). No Franz
+Lisp executable file should EVER be stripped.
+
+Tim Maroney
+tim.unc@udel-relay
+decvax!duke!unc!tim
+
+From Mark.Sherman@CMU-CS-A  Sat Feb 12 21:38:46 1983
+Date: 13 February 1983 0034-EST (Sunday)
+From: Mark.Sherman@CMU-CS-A
+Subject: Space and Leakage
+Message-Id: <13Feb83 003422 MS40@CMU-CS-A>
+Received: from CMU-CS-A by UCBVAX.BERKELEY.ARPA (3.300 [1/17/83])
+       id AA07842; 12 Feb 83 21:38:46 PST (Sat)
+Received: by UCBKIM.ARPA (3.310/3.3)
+       id AA02341; 14 Feb 83 16:21:29 PST (Mon)
+To: franz-friends@UCB-VAX
+Status: O
+
+Can someone tell me how the maximum amount of storage that franz
+lisp uses is decided? I can force the size up to (about) 3050
+pages (according to "ps") and then get the message "storage exhausted".
+I have been told (and have seen) other jobs get substantially more
+space; can franz get more pages as well? (I am using the cshell
+and have already used the limit command to raise my process
+size up to 32 megabytes, or so I think.)
+I have also been told that the garbage collector leaks, that is,
+not all of the garbage is really collected. Does anyone have good
+ideas about how much (or fast) this happens, or if there is some way
+to minimize the lost space?
+(Please send responses directly to me as I am not on this list.)
+                        -Mark Sherman (Sherman@CMU-CS-A)
+
+From @udel-relay:Mac.uvacs.Virginia@UDel-Relay  Fri Feb 18 21:04:31 1983
+Date:     18 Feb 83 12:42:40-EST (Fri)
+From: Mac.uvacs@UDel-Relay
+Subject:  global nonspecial variables
+Return-Path: <Mac.uvacs.Virginia@UDel-Relay>
+Message-Id: <8302190504.26020@UCBVAX.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.ARPA (3.312/3.5)
+       id AA26020; 18 Feb 83 21:04:31 PST (Fri)
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA00656; 21 Feb 83 01:59:26 PST (Mon)
+To: FRANZ-FRIENDS@BERKELEY.ARPA
+Via:  Virginia; 18 Feb 83 23:58-EST
+Status: O
+
+Does the Liszt compiler have any notion of global variables --
+free variables with fast access, without any rebinding?
+
+I think the MACLISP compiler has something like this for variables
+beginning "**".
+
+                               Alex Colvin
+
+                               uucp: ...decvax!duke!mcnc!ncsu!uvacs!mac
+                               csnet:mac@virginia
+                               arpa: mac.uvacs@udel-relay
+
+From jkf@UCBKIM  Mon Feb 21 09:19:56 1983
+Date: 21 Feb 83 09:19:43 PST (Mon)
+From: jkf@UCBKIM (John Foderaro)
+Subject: Re:  global nonspecial variables
+Message-Id: <8302211719.2798@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA02798; 21 Feb 83 09:19:43 PST (Mon)
+Received: from UCBKIM.ARPA by UCBVAX.ARPA (3.314/3.5)
+       id AA13982; 21 Feb 83 09:11:52 PST (Mon)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA02805; 21 Feb 83 09:19:56 PST (Mon)
+To: Mac.uvacs@UDel-Relay, FRANZ-FRIENDS@BERKELEY.ARPA
+In-Reply-To: Your message of     18 Feb 83 12:42:40-EST (Fri)
+Status: O
+
+  I don't understand the distinction between what you call a global variable
+and a special variable.   A special variable in Franz Lisp (and any other
+shallow bound lisp) can be accessed rapidly and is only rebound if you
+put it in a lambda, prog or do variable list.
+
+
+
+From jkf@UCBKIM  Fri Feb 25 08:29:01 1983
+Date: 25 Feb 83 08:28:45 PST (Fri)
+From: jkf@UCBKIM (John Foderaro)
+Subject: research position at edinburgh
+Message-Id: <8302251628.528@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA00528; 25 Feb 83 08:28:45 PST (Fri)
+Received: from UCBKIM.ARPA by UCBVAX.ARPA (3.314/3.5)
+       id AA00867; 25 Feb 83 08:18:48 PST (Fri)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA00537; 25 Feb 83 08:29:01 PST (Fri)
+To: franz-friends@BERKELEY.ARPA
+Status: O
+
+
+                    DEPARTMENT OF ARTIFICIAL INTELLIGENCE
+                           UNIVERSITY OF EDINBURGH
+
+                              RESEARCH FELLOW
+
+A Research Fellowship is available within the Programming Systems Development
+Group.  The post has been created specifically to provide a modern LISP system
+for the Perq computer running under ICL MicroCode UNIX, and is funded by the
+Science and Engineering Research Council.
+
+Experience in implementing systems would be advantageous, as would be a
+knowledge of LISP and C.  Access will be available to an SERC DECsystem-10
+running TOPS-10 and to a University VAX 750 running Berkeley UNIX, as well as
+to Perqs.
+
+The appointment will be made on the salary range 1B/1A, 5550 - 10670 pounds
+sterling, according to age and experience.  The post is funded for a period of
+two years from the date of appointment.
+
+Further particulars of the post can be obtained from:
+
+       Administrative Assistant
+       Department of Artificial Intelligence
+       University of Edinburgh
+       Forrest Hill
+       Edinburgh  EH1 2QL
+       SCOTLAND
+phone
+       031-667-1011 x2554
+
+or by contacting
+
+       RAE%EDXA%UCL-CS@ISID            (Networks permitting)
+
+Applications should be made by March 17th, 1983.
+
+
+
+
+From layer  Sat Mar  5 20:12:57 1983
+Date: 5 Mar 83 20:12:57 PST (Sat)
+From: layer (Kevin Layer)
+Subject: process function
+Message-Id: <8303060412.18927@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA18927; 5 Mar 83 20:12:57 PST (Sat)
+Phone: (415) 652-2405
+To: local-lisp
+Status: O
+
+The process function now looks in the environment at the SHELL variable.
+If present, it will use this as the default shell to execute your command.
+If not present, csh and then sh are tried (in that order).
+
+
+From @udel-relay.ARPA:Pintzuk.UPenn.UPenn@UDel-Relay  Tue Mar  8 06:04:10 1983
+Date:  8 Mar 1983  2:32-EST
+From: Susan Pintzuk <Pintzuk.UPenn@UDel-Relay>
+Subject: lisp statistical packages
+Return-Path: <Pintzuk.UPenn.UPenn@UDel-Relay>
+Message-Id: <8303081401.AA13004@UCBVAX.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.ARPA (3.322/3.14)
+       id AA13004; 8 Mar 83 06:01:54 PST (Tue)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA08297; 8 Mar 83 06:04:10 PST (Tue)
+To: franz-friends@BERKELEY.ARPA
+Via:  UPenn; 8 Mar 83 3:49-EST
+Status: O
+
+do any franz-lisp packages exist which calculate mean, standard deviation,
+%n within mean +/- 1 (or 2 or 3) standard deviation(s), etc.?  if so, how
+do i obtain a copy?
+
+From jkf  Tue Mar  8 09:10:46 1983
+Date: 8 Mar 83 09:10:46 PST (Tue)
+From: jkf (John Foderaro)
+Subject: opus38.56
+Message-Id: <8303081710.9423@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA09423; 8 Mar 83 09:10:46 PST (Tue)
+To: local-lisp
+Status: O
+
+  If $gcprint is set to a non nil value, then just before a garbage
+collection is begun, the message 'gc:' will be printed on the tty.
+As before, after the garbage collection is finished, the statistics
+message in square brackets will be printed.
+
+
+
+From fateman  Wed Mar  9 09:54:31 1983
+Date: 9 Mar 83 09:54:31 PST (Wed)
+From: fateman (Richard Fateman)
+Subject: need a job 
+Message-Id: <8303091754.14754@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA14754; 9 Mar 83 09:54:31 PST (Wed)
+To: local-lisp
+Status: O
+
+porting Lisp, C, Pascal, Fortran ... etc to a Denelcorp HEP
+computer?  Wanna live in Denver?  There is a recruiter in
+town from Denelcor at Marriot Inn, Jim Holly.  There is an
+ad posted on 5th floor bulletin board.
+
+From jkf  Sat Mar 19 17:44:33 1983
+Date: 19 Mar 83 17:44:33 PST (Sat)
+From: jkf (John Foderaro)
+Subject: liszt 8.24
+Message-Id: <8303200144.25091@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA25091; 19 Mar 83 17:44:33 PST (Sat)
+To: local-lisp
+Status: O
+
+  The vax and 68k versions of liszt have been combined into one set of
+source files.  This is mainly a textual change, but some functions
+in the compiler have been modified in reduce the machine dependent code.
+Be on the lookout for strange errors.
+
+
+
+From fateman  Tue Mar 22 20:52:11 1983
+Date: 22 Mar 83 20:52:11 PST (Tue)
+From: fateman (Richard Fateman)
+Subject: T Lisp
+Message-Id: <8303230452.5935@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA05935; 22 Mar 83 20:52:11 PST (Tue)
+To: local-lisp
+Status: RO
+
+I have a preliminary manual for the T dialect of Lisp, created
+at Yale.  It is being offered for sale by Cognitive Systems, Inc.
+for $1000/CPU (educational price).  It offers features from Lisp
+and Scheme.  It runs on VAX and Apollo 68000 systems.  
+
+From jkf  Thu Mar 24 08:29:31 1983
+Date: 24 Mar 83 08:29:31 PST (Thu)
+From: jkf (John Foderaro)
+Subject: liszt 8.25
+Message-Id: <8303241629.6735@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA06735; 24 Mar 83 08:29:31 PST (Thu)
+To: local-lisp
+Status: O
+
+
+  If you do this:
+
+  liszt -x a/b/c.l -o x/y/z.o
+
+  then the cross reference file will be put in x/y/z.x 
+  Before this version, it would have gone into a/b/c.x
+  
+
+
+From jkf  Thu Mar 24 15:00:37 1983
+Date: 24 Mar 83 15:00:37 PST (Thu)
+From: jkf (John Foderaro)
+Subject: liszt 8.26
+Message-Id: <8303242300.11144@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA11144; 24 Mar 83 15:00:37 PST (Thu)
+To: local-lisp
+Status: O
+
+  liszt will now pass the assembler the -V switch.  This tells the assembler
+to keep its intermediate file in core rather than putting it in /tmp.
+This should make assembly slightly faster and also permit large lisp files to
+be compiled on systems with small /tmp's.
+
+
+
+From @udel-relay.ARPA:tim.unc@UDel-Relay  Sat Mar 26 03:41:05 1983
+Date:     25 Mar 83 15:03:29 EST  (Fri)
+From: Tim Maroney <tim.unc@UDel-Relay>
+Subject:  open coding of (function (lambda ...))
+Return-Path: <tim.unc@UDel-Relay>
+Message-Id: <8303261137.AB02371@UCBVAX.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.ARPA (3.331/3.17)
+       id AB02371; 26 Mar 83 03:37:13 PST (Sat)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA00854; 26 Mar 83 03:41:05 PST (Sat)
+To: franz-friends@BERKELEY.ARPA
+Via:  UNC; 25 Mar 83 19:43-EST
+Status: O
+
+This doesn't seem to work. I'm using Liszt version 8.10, University
+of Maryland distribution. The documentation in the file "lispnews"
+is sketchy, but it seems that compiling and loading the file:
+
+(setq appsum (function (lambda (x) (apply 'sum x))))
+
+should leave a bcd object in appsum's value, but it doesn't. It
+leaves the uncompiled lambda. Am I doing something wrong? 
+
+Tim Maroney
+decvax!duke!unc!tim
+tim.unc@udel-relay
+
+From jkf@UCBKIM  Sat Mar 26 08:46:44 1983
+Date: 26 Mar 83 08:46:28 PST (Sat)
+From: jkf@UCBKIM (John Foderaro)
+Subject: Re:  open coding of (function (lambda ...))
+Message-Id: <8303261646.2453@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA02453; 26 Mar 83 08:46:28 PST (Sat)
+Received: from UCBKIM.ARPA by UCBVAX.ARPA (3.331/3.17)
+       id AA05012; 26 Mar 83 08:42:50 PST (Sat)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA02462; 26 Mar 83 08:46:44 PST (Sat)
+To: tim.unc@UDel-Relay
+Cc: franz-friends@BERKELEY.ARPA
+In-Reply-To: Your message of     25 Mar 83 15:03:29 EST  (Fri)
+Status: O
+
+
+   Liszt only compiles functions, not literals it finds in files.
+To make this statement be compiled:
+(setq appsum (function (lambda (x) (apply 'sum x))))
+
+you should surround it with a function defintion:
+(defun junk ()
+       (setq appsum (function (lambda (x) (apply 'sum x)))))
+
+
+
+From CARR@UTAH-20  Mon Apr  4 14:53:09 1983
+Date:  4 Apr 1983 0922-MST
+From: Harold Carr <CARR@UTAH-20>
+Subject: Franz/Common lisp
+Message-Id: <8304041711.AA07020@UCBVAX.ARPA>
+Received: from UTAH-20 (utah-20.ARPA) by UCBVAX.ARPA (3.332/3.20)
+       id AA07020; 4 Apr 83 09:11:40 PST (Mon)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA01683; 4 Apr 83 14:53:09 PST (Mon)
+To: franz-friends@BERKELEY.ARPA
+Cc: KROHNFELDT@UTAH-20
+Status: O
+
+Does anyone have any sort of Common Lisp compatibility package for Franz?
+If so, how can I obtain it? Thanks in advance. Harold Carr (CARR@UTAH-20).
+-------
+
+From jeff@aids-unix  Tue Apr  5 12:42:46 1983
+Date:  4 Apr 1983 11:06:49 PST (Monday)
+From: Jeff Dean <jeff@aids-unix>
+Subject: knowledge representation language
+Message-Id: <8304052042.AA26557@UCBVAX.ARPA>
+Received: from aids-unix (aids-unix.ARPA) by UCBVAX.ARPA (3.332/3.20)
+       id AA26557; 5 Apr 83 12:42:11 PST (Tue)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA16443; 5 Apr 83 12:42:46 PST (Tue)
+To: franz-friends@BERKELEY.ARPA
+Status: O
+
+Does anyone have a knowledge representation language (such as FRL or
+KL-ONE) available under Franz Lisp?
+
+       Jeff Dean
+       arpa: jeff@aids-unix
+       uucp: ...ucbvax!jeff@aids-unix
+
+
+From jkf  Tue Apr  5 13:08:06 1983
+Date: 5 Apr 83 13:08:06 PST (Tue)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.57
+Message-Id: <8304052108.16969@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA16969; 5 Apr 83 13:08:06 PST (Tue)
+To: local-lisp
+Status: RO
+
+  This version has a number of internal changes to make it compilable
+on 68k.  If you notice it acting abnormally, let me know.
+
+
+
+From FAHLMAN@CMU-CS-C  Thu Apr  7 07:50:06 1983
+Date: Thu, 7 Apr 1983  10:46 EST
+From: Scott E. Fahlman <Fahlman@CMU-CS-C>
+Subject: Franz/Common lisp
+Message-Id: <8304071549.AA13873@UCBVAX.ARPA>
+Received: ID <FAHLMAN@CMU-CS-C>; 7 Apr 83 10:46:59 EST
+Received: from CMU-CS-C (cmu-cs-c.ARPA) by UCBVAX.ARPA (3.332/3.20)
+       id AA13873; 7 Apr 83 07:49:42 PST (Thu)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA18082; 7 Apr 83 07:50:06 PST (Thu)
+To: Harold Carr <CARR@UTAH-20>
+Cc: franz-friends@BERKELEY.ARPA
+In-Reply-To: Msg of 4 Apr 1983  11:22-EST from Harold Carr <CARR at UTAH-20>
+Status: RO
+
+
+Harold,
+
+A couple of things make it seem unlikely that anyone would have such a
+package right now.  First, we don't even have a final Common Lisp manual
+yet -- Guy's next draft is due very soon, but there will be some tuning
+and hassling after that.  Second, there are things in Common Lisp that
+would be very tough to fake on Franz: lexical binding, generic
+sequences, some of the hairy number types, character objects, etc.
+Common Lisp is pretty close to being a superset of Franz, so I would
+expect to see Franz compatibility packages in Common Lisp, but not vice
+versa.  Third, if anyone were writing such a package, they would be
+crazy not to have arranged for access to our code that implements all of
+the hairy functions, and nobody has done this to my knowledge.
+
+My standard advice is for people to continue to code in Franz with the
+knowledge that they can easily convert their code to Common Lisp
+whenever the DEC Common Lisp is available to them.  This should be a
+one-time conversion, since moving the other way after "going native" in
+Common Lisp would be very tough.
+
+If someone does pop up with a compatibility package -- even a partial
+one -- I would be interested in hearing about it.
+
+-- Scott
+
+From fateman@UCBKIM  Sun Apr 10 19:52:14 1983
+Date: 10 Apr 83 19:50:59 PST (Sun)
+From: fateman@UCBKIM (Richard Fateman)
+Subject: Re:  Franz/Common lisp
+Message-Id: <8304110350.6176@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA06176; 10 Apr 83 19:50:59 PST (Sun)
+Received: from UCBKIM.ARPA by UCBVAX.ARPA (3.332/3.21)
+       id AA10019; 10 Apr 83 19:49:55 PST (Sun)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA06192; 10 Apr 83 19:52:14 PST (Sun)
+To: carr@utah-20, fahlman@cmu-cs-c
+Cc: franz-friends@BERKELEY.ARPA
+Status: RO
+
+I think that a common-lisp-compatibility package written
+in Franz would not be as difficult as all that. 
+
+If Common Lisp (TM of DEC?) were available on all the same
+machines at the same price, (appx. $0.) and CL were
+in fact a superset of Franz for all practical purposes, and
+with similar or better efficiency, etc. Why would anyone bother?
+
+Of course if CL does not meet all of the objectives (e.g. price, machines),
+then a CL-to-Franz "translator" might make sense.
+
+With that in mind,
+I would like to officially request a copy of the Common Lisp
+language (as implemented in CL, presumably), as soon as it
+becomes available (i.e. no later than when it is a "product"
+of DEC, and probably at "beta" test time).
+I agree fully with Scott that trying to do this with an incomplete
+language specification is unwise.
+
+I am also not making any commitment to do anything with CL at
+Berkeley, but since we are building tools for our own applications,
+and CL might be useful, we might consider an efficient merge of
+ideas.
+
+From jkf@UCBKIM  Mon Apr 11 08:07:39 1983
+Date: 11 Apr 83 06:42:43 PST (Mon)
+From: jkf@UCBKIM (John Foderaro)
+Subject: mail to this mailing list
+Message-Id: <8304111442.11378@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA11378; 11 Apr 83 06:42:43 PST (Mon)
+Received: from UCBKIM.ARPA by UCBVAX.ARPA (3.332/3.21)
+       id AA07288; 11 Apr 83 08:05:32 PST (Mon)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.310/3.5)
+       id AA11949; 11 Apr 83 08:07:39 PST (Mon)
+To: franz-friends@BERKELEY.ARPA
+Status: RO
+
+  I'm sorry that people who mail to this mailing list must put up with lots
+ of mail errors from our local mailer.   The problem is not that we have a
+ lot of illegal addresses, but that over the three day period that the
+ mailer tries to deliver the mail, some of the destination sites never
+ respond.  I think that this is due primarily to the fact that many sites
+ are running new mail and networking software.   Hopefully this will
+ improve over time.
+                                       john foderaro
+                                       
+
+
+
+From jkf  Fri Apr 22 09:59:09 1983
+Date: 22 Apr 83 09:59:09 PST (Fri)
+From: jkf (John Foderaro)
+Subject: lisp opus 38.59
+Message-Id: <8304221759.20996@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA20996; 22 Apr 83 09:59:09 PST (Fri)
+To: local-lisp
+Status: RO
+
+  Input like 1.2.3 and 1..2  will now be read as single symbols rather
+than two consecutive numbers.
+
+
+
+From jkf  Sun May  8 00:02:54 1983
+Date: 8 May 83 00:02:54 PDT (Sun)
+From: jkf (John Foderaro)
+Subject: opus 38.60
+Message-Id: <8305080702.22344@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.310/3.5)
+       id AA22344; 8 May 83 00:02:54 PDT (Sun)
+To: local-lisp
+Cc: rms
+Status: RO
+
+ Thanks to some suggestions from rms we are now one step closer to
+full closures.   fclosures will now work if called recursively.
+It is still true that the only way to make fclosures share variables
+is to use fclosure-list.
+
+ symeval-in-fclosure may return the wrong value if the closure is 
+'active'.  This will be fixed eventually.
+
+
+
+From mbr@nprdc  Sat May 21 07:37:23 1983
+Date: 20 May 1983 14:57:55-PDT
+From: mbr@NPRDC
+Subject: lam9.c and curses
+Message-Id: <8305211434.AA16172@UCBVAX.ARPA>
+Received: from nprdc (nprdc.ARPA) by UCBVAX.ARPA (3.341/3.29)
+       id AA16172; 21 May 83 07:34:43 PDT (Sat)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA08856; 21 May 83 07:37:23 PDT (Sat)
+Reply-To: mbr <mbr@NPRDC>
+To: franz-friends@BERKELEY.ARPA
+Cc: mbr@NPRDC
+Status: O
+
+When we attempted to cfasl a file that used the curses package
+of screen control routines into Franz 38.40, we got the message
+_ospeed: /usr/libcurses.a (cr_tty.o) multiply defined.
+The apparent cause of this cryptic remark is that in lam9.c
+there is an extern variable ospeed. There are a number of
+tantalizing routines in this source file dealing with termcaps that
+are apparently not called by anyone. Are there plans for these
+routines? Does anyone use them (heaven forbid they should be
+documented!). Our current fix is to just change ospeed to ospiid
+which so far has had no dire effects, but I am interested in others
+experience. The curses stuff seems to work fine after this
+modification.
+                       Mark Rosenstein
+
+
+From jkf  Wed May 25 12:15:54 1983
+Date: 25 May 83 12:15:54 PDT (Wed)
+From: jkf (John Foderaro)
+Subject: opus 38.61
+Message-Id: <8305251915.1144@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA01144; 25 May 83 12:15:54 PDT (Wed)
+To: local-lisp
+Status: O
+
+  symeval-in-fclosure and set-in-fclosure now work (thanks to keith).
+
+  selectq is now a part of standard franz.  selectq is just like
+ caseq except it allows 'otherwise' as well as 't' for the
+ key which means 'if nothing else matches, use this clause'.
+
+
+From cornwell@nrl-css  Wed May 25 12:51:17 1983
+Date: Wed, 25 May 83 15:14:19 EDT
+From: Mark Cornwell <cornwell@NRL-CSS>
+Subject: Franz on the Sun
+Message-Id: <8305251950.AA02600@UCBVAX.ARPA>
+Received: from nrl-css (nrl-css.ARPA) by UCBVAX.ARPA (3.341/3.29)
+       id AA02600; 25 May 83 12:50:26 PDT (Wed)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA01878; 25 May 83 12:51:17 PDT (Wed)
+To: franz-friends@BERKELEY.ARPA
+Cc: cornwell@NRL-CSS
+Status: O
+
+
+  Our group at NRL is planning to purchase Sun workstations. I
+currently have a substantial amount of code written in Franz Lisp that
+I want to run on the Sun. 
+  What is the status of the Berkeley group porting Franz to the Sun?   
+How do I get a copy?
+
+  Also, I have a few concerns about configuring a Sun to run Franz well.  
+The basic desktop Sun workstation provides 1 Mbyte of physical memory.   
+This can be extended to 2 Mbyte or one can add an Ethernet interface
+*but not both*.  Since I am unwilling to give up my Ethernet
+interface I may be forced to run Franz in 1 Mbyte and contend with
+the added paging overhead (using a 68010 running 4.2bsd and a local disk).
+
+  Has anyone out there had experience running Franz Lisp on a Sun in
+such a configuration?  Can I get away without the 2 Mbyte extension?
+I think your answers would be of general interest. 
+
+-- Mark (caught between a rock and a hard place?) Cornwell
+
+
+From baden@UCBKIM  Wed May 25 13:51:39 1983
+Date: 25 May 83 13:32:01 PDT (Wed)
+From: baden@UCBKIM (Scott B. Baden)
+Subject: Re:  Franz on the Sun
+Message-Id: <8305252032.2716@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA02716; 25 May 83 13:32:01 PDT (Wed)
+Received: from UCBKIM.ARPA by UCBVAX.ARPA (3.341/3.29)
+       id AA03753; 25 May 83 13:50:52 PDT (Wed)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA03002; 25 May 83 13:51:39 PDT (Wed)
+To: franz-friends@BERKELEY.ARPA
+Cc: cornwell@NRL-CSS
+Status: O
+
+Which sun are you using?  My office mate says that
+he has seen a sun configured with 2MB of memory AND
+an Ethernet board.
+
+From mike%Rice.Rice@Rand-Relay  Fri May 27 19:51:33 1983
+Date:     Fri, 27 May 83 18:18:47 CDT
+From: Mike.Caplinger <mike.rice@Rand-Relay>
+Subject:  Re:  Franz on the Sun
+Return-Path: <mike%Rice.Rice@Rand-Relay>
+Message-Id:  <1983.05.27.18.18.47.150.08942@dione.rice>
+Received: from rand-relay.ARPA by UCBVAX.ARPA (3.341/3.29)
+       id AA19088; 27 May 83 19:50:15 PDT (Fri)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA02221; 27 May 83 19:51:33 PDT (Fri)
+To: franz-friends@BERKELEY.ARPA
+In-Reply-To: baden%UCBKIM's message of 25 May 83 13:32:01 PDT (Wed)
+Via:  Rice; 27 May 83 19:14-PDT
+Status: RO
+
+As I type I'm bringing up the 68K version of Opus 38 (now FTPable from
+UCB-VAX) on a SUN running 4.1c.  There don't seem to be any major
+problems so far, but the compiler doesn't run on a system with all the
+net servers on it because it runs out of memory.  I've been told this
+is because there's a bug in 4.1c that forces it to only use 1/2 of the
+swap partition.  I'm having to run standalone to compile the compiler;
+I don't yet know whether I'll be able to compile other stuff without
+this rather extreme fix.
+
+As I use the system more I will post more info to this group.
+
+From narain@rand-unix  Tue May 31 10:49:00 1983
+Date: Tuesday, 31 May 1983 10:45-PDT
+From: narain@rand-unix
+Subject: Interrupt question
+Message-Id: <8305311747.AA10893@UCBVAX.ARPA>
+Received: from rand-unix (rand-unix.ARPA) by UCBVAX.ARPA (3.341/3.29)
+       id AA10893; 31 May 83 10:47:26 PDT (Tue)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA13428; 31 May 83 10:49:00 PDT (Tue)
+To: franz-friends@BERKELEY.ARPA
+Cc: narain@rand-unix
+Status: O
+
+
+Hi, I would be grateful if you could tell me  what  is  the  equivalent  of
+Interlisp's  control-h  (followed  by  OK) in Franzlisp.  In other words, I
+wish to interrupt a Franzlisp program, from time to time, examine its state
+and allow it to continue from the interrupted point.
+
+-- Sanjai
+
+From lbl-csam!steve@ssc-vax.UUCP  Tue May 31 19:31:04 1983
+Date: 31 May 83 17:28:35 PDT (Tue)
+From: ssc-vax!steve@lbl-csam.UUCP
+Subject: packages
+Message-Id: <8306010028.AA16451@LBL-CSAM.ARPA>
+Received: by LBL-CSAM.ARPA (3.320/3.21)
+       id AA16451; 31 May 83 17:28:35 PDT (Tue)
+Received: by UCBVAX.ARPA (3.341/3.31)
+       id AA02877; 31 May 83 19:30:00 PDT (Tue)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA22745; 31 May 83 19:31:04 PDT (Tue)
+To: ucbvax!franz-friends@lbl-csam.UUCP
+Status: O
+
+
+Does a version of LispMachine ``packages'' or some similar oblist partitioning
+scheme exist for franz?  Having just integrated several independently coded
+modules, I think something like that would be very useful.
+                                       -thanks
+       Steve White, BAC, {uw-beaver,lbl-csam}!ssc-vax!steve
+
+
+From fateman  Tue Jun 14 11:48:32 1983
+Date: 14 Jun 83 11:48:32 PDT (Tue)
+From: fateman (Richard Fateman)
+Subject: "macsyma on a chip?"
+Message-Id: <8306141848.6756@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA06756; 14 Jun 83 11:48:32 PDT (Tue)
+To: macsyma-i@mit-mc
+Cc: franz-friends
+Status: O
+
+Well, sort of. We now have Macsyma running on a Motorola 68000 - based
+system with 6 megabytes of real memory. The operating system is a 
+Unisoft UNIX system, which has been ported to some large number (>65) boxes.  
+The Pixel people were kind enough to lend us a machine with enough 
+real memory to make virtual memory unnecessary.
+
+It takes a long time to load up, but once running, it is quite responsive,
+and appears to be about 60% of a VAX 11/780 in terms of CPU time. 
+
+We have not shaken down everything, but since the source code is unchanged
+from the VAX, we expect the bugs to be limited to lisp compilation
+glitches, or differences between versions of the UNIX system.
+
+
+From jkf  Wed Jun 15 10:42:05 1983
+Date: 15 Jun 83 10:42:05 PDT (Wed)
+From: jkf (John Foderaro)
+Subject: Opus 38.62
+Message-Id: <8306151742.20591@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA20591; 15 Jun 83 10:42:05 PDT (Wed)
+To: local-lisp
+Status: O
+
+  There is no longer a limit on the size of bignums, strings or
+symbol names which can be read by the reader [other than the size of
+virtual memory].
+
+  The value of lisp-library-directory will determine where cfasl finds
+its private version of the loader.
+
+ (changes by sklower)
+
+
+From @CMU-CS-C:UI.TYJ@CU20D  Wed Jun 15 18:22:55 1983
+Date: 14 Jun 1983 1812-EDT
+From: Tai Jin <UI.TYJ@CU20D>
+Subject: franz mailing liszt
+Message-Id: <8306142214.AA16599@UCBVAX.ARPA>
+Received: from CMU-CS-C (cmu-cs-c.ARPA) by UCBVAX.ARPA (3.346/3.33)
+       id AA16599; 14 Jun 83 15:14:36 PDT (Tue)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA28806; 15 Jun 83 18:22:55 PDT (Wed)
+To: franz-friends%berkeley@CMCSC
+Cc: ui.travis%cu20d@CMCSC, ui.tyj%cu20d@CMCSC
+Status: O
+
+
+Hi, we would like to be added to your mailing list.
+
+We are currently attempting to install FRANZ Lisp on Amdahl's Unix (UTS)
+running under VM/CMS on an IBM 4341 here at CUCCA (Columbia University Center
+for Computing Activities).
+
+Is anyone out there working on an UTS/IBM implementation?  Any information will
+be greatly appreciated.
+
+
+Thanks,
+
+Tai Jin <UI.TYJ%CU20D@CMCSC>
+Travis Winfrey <UI.TRAVIS%CU20D@CMCSC>
+-------
+
+From @CMU-CS-C:Ui.Travis@CU20D  Thu Jun 16 09:47:39 1983
+Date: 16 Jun 1983 1243-EDT
+From: Travis Lee Winfrey <Ui.Travis@CU20D>
+Subject: Porting Franz lisp to Amdahl Unix
+Message-Id: <8306161646.AA25470@UCBVAX.ARPA>
+Received: from CMU-CS-C (cmu-cs-c.ARPA) by UCBVAX.ARPA (3.346/3.33)
+       id AA25470; 16 Jun 83 09:46:15 PDT (Thu)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA06352; 16 Jun 83 09:47:39 PDT (Thu)
+To: sklower%berkeley@CMCSC, kim.layer%berkeley@CMCSC
+Cc: franz-friends%berkeley@CMCSC, ui.tyj@CU20D, Ui.Travis@CU20D,
+        kim.fateman%berkeley@CMCSC
+Status: O
+
+Hi, Tai Jin and I are currently attemping to bring up Franz lisp on Amdahl's
+Unix running on a IBM 4341.  We are working from a copy that runs on the VAX.
+
+We would be very interested in seeing any versions that runs both on the VAX
+and some other machine, such as the 68000.  We are also interested in seeing
+any documentation on other porting efforts, regardless of what machine.
+
+Thanks,
+
+Tai Jin  <ui.tyj%cu20d@cmu-cs-c>
+Travis Winfrey <ui.travis%cu20d@cmu-cs-c>
+-------
+
+From jkf  Sun Jun 19 15:43:34 1983
+Date: 19 Jun 83 15:43:34 PDT (Sun)
+From: jkf (John Foderaro)
+Subject: opus 38.63
+Message-Id: <8306192243.19626@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA19626; 19 Jun 83 15:43:34 PDT (Sun)
+To: local-lisp
+Status: O
+
+ Added functions:
+   (vputprop 'Vv_vector 'g_value 'g_indicator)
+   (vget  'Vv_vector 'g_indicator)
+
+  work just like putprop and get, but modify the vector property list.
+
+ Also:
+   you can determine which function is called by lisp to print a vector
+ by placing the function to call on the vector's property list under
+ indicator 'print'.  The  print function is called with two arguments:
+ the vector and the port.
+ For example:
+=> (defun printv (v port)
+      (patom "A vector of size " port)
+      (print (vsize v) port))
+printv
+=> (setq xx (new-vector 10))
+vector[40]
+=> (vputprop xx 'printv 'print)
+printv
+=> xx
+A vector of size 10
+=>
+
+
+
+From jkf  Sun Jun 19 22:47:42 1983
+Date: 19 Jun 83 22:47:42 PDT (Sun)
+From: jkf (John Foderaro)
+Subject: opus 38.64
+Message-Id: <8306200547.23164@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA23164; 19 Jun 83 22:47:42 PDT (Sun)
+To: local-lisp
+Cc: jpg@Mit-mc
+Status: O
+
+
+  added the function (^ 'x_a 'x_b)  which computes  x_a to the x_b
+power and always returns a fixnum result (it currently wraps around
+on overflow).
+
+
+
+From JPG@MIT-MC  Sun Jun 19 22:54:00 1983
+Date: 20 June 1983 01:53 EDT
+From: Jeffrey P. Golden <JPG@MIT-MC>
+Subject: ^
+Message-Id: <8306200553.AA15160@UCBVAX.ARPA>
+Received: from MIT-MC (mit-mc.ARPA) by UCBVAX.ARPA (3.346/3.33)
+       id AA15160; 19 Jun 83 22:53:57 PDT (Sun)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA23228; 19 Jun 83 22:54:00 PDT (Sun)
+To: jkf@UCBKIM
+Cc: JPG@MIT-MC, local-lisp@UCBKIM
+Status: O
+
+   Date: 19 Jun 83 22:47:42 PDT 
+   From: jkf%UCBKIM@Berkeley 
+   Subject: opus 38.64
+   To: local-lisp%UCBKIM@Berkeley
+   Cc: jpg@Mit-mc
+   added the function (^ 'x_a 'x_b)  which computes  x_a to the x_b
+   power and always returns a fixnum result (it currently wraps around
+   on overflow).
+The Maclisp ^ errors out in this case with the message:
+;RESULT LARGER THAN FIXNUM - ^
+
+
+From narain@rand-unix  Mon Jun 20 22:09:31 1983
+Date: Monday, 20 Jun 1983 22:00-PDT
+From: narain@rand-unix
+Subject: Re: Interrrupt question
+Message-Id: <8306210509.AA00276@UCBVAX.ARPA>
+Received: from rand-unix (rand-unix.ARPA) by UCBVAX.ARPA (3.346/3.33)
+       id AA00276; 20 Jun 83 22:09:20 PDT (Mon)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA09633; 20 Jun 83 22:09:31 PDT (Mon)
+To: franz-friends@BERKELEY.ARPA
+Cc: narain@rand-unix
+Status: O
+
+
+                                  TWIMC
+                                  -----
+
+Here is the equivalent of Interlisp's control-H followed by OK in Franzlisp:
+i.e. if you wish to interrupt a Franzlisp computation, browse around the state
+and resume computation:
+
+Hit DEL;
+Browse;
+(return t)
+
+This answer was given by Liz Allen at Maryland (liz.umcp-cs@udel-relay).
+
+-- Sanjai
+
+From Tim%UPenn.UPenn@UDel-Relay  Tue Jun 21 14:52:53 1983
+Date: Tue, 21 Jun 83 10:33 EDT
+From: Tim Finin <Tim.UPenn@UDel-Relay>
+Subject: interrupting Franz
+Return-Path: <Tim%UPenn.UPenn@UDel-Relay>
+Message-Id: <8306212152.AA12930@UCBVAX.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.ARPA (3.346/3.33)
+       id AA12930; 21 Jun 83 14:52:36 PDT (Tue)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA21097; 21 Jun 83 14:52:53 PDT (Tue)
+To: franz-friends@BERKELEY.ARPA
+Via:  UPenn; 21 Jun 83 17:40-EDT
+Status: O
+
+
+Under VMS, one should type a ^C (control-C) rather than DEL to interrupt Franz.
+
+From jkf  Sat Jun 25 13:49:37 1983
+Date: 25 Jun 83 13:49:37 PDT (Sat)
+From: jkf (John Foderaro)
+Subject: opus 38.65
+Message-Id: <8306252049.25527@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA25527; 25 Jun 83 13:49:37 PDT (Sat)
+To: local-lisp
+Status: O
+
+  If you have automatic case conversion set (i.e. (sstatus uctolc t)),
+then symbols with lower case letters will be escaped by print.
+
+
+
+From layer  Tue Jul  5 00:26:29 1983
+Date:  5 Jul 1983 0026-PDT (Tuesday)
+From: layer (Kevin Layer)
+Subject: lisp opus 38.67
+Message-Id: <5390.30.426237985@ucbkim>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA05911; 5 Jul 83 00:26:29 PDT (Tue)
+Phone: (415) 652-2405
+To: local-lisp
+Cc: layer
+Status: O
+
+  The function 'sortcar' has been slightly changed: if the second
+arg is nil, then the ordering function 'alphalessp' is assumed
+('sort' does it this way).
+
+       Kevin
+
+From layer  Wed Jul  6 00:02:33 1983
+Date: 6 Jul 83 00:02:33 PDT (Wed)
+From: layer (Kevin Layer)
+Subject: liszt opus 8.30
+Message-Id: <8307060702.24776@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA24776; 6 Jul 83 00:02:33 PDT (Wed)
+Phone: (415) 652-2405
+To: local-lisp
+Cc: sklower, jkf
+Status: O
+
+  All modifications should be transparent, but if there are problems
+relating to the autorun feature (-r flag), please let me know.
+
+       Kevin
+
+
+
+From sklower  Thu Jul  7 00:27:52 1983
+Date: 7 Jul 83 00:27:52 PDT (Thu)
+From: sklower (Keith Sklower)
+Subject: Franz, opus38.68
+Message-Id: <8307070727.10697@UCBKIM.ARPA>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA10697; 7 Jul 83 00:27:52 PDT (Thu)
+To: local-lisp
+Status: O
+
+Franz now escapes UPPER case letters instead of lower case letters when
+(status uctolc) is enabled, so that (read (print x)) is an identity operation
+on atom printnames.  Also, we made (explode) conform to what maclisp does
+with opposite-than-normal character-cases.
+
+From Ira%UPenn.UPenn@UDel-Relay  Fri Jul  8 01:46:25 1983
+Date: Thu, 7 Jul 83 22:13 EDT
+From: Ira Winston <Ira.UPenn@UDel-Relay>
+Subject: Eliza
+Return-Path: <Ira%UPenn.UPenn@UDel-Relay>
+Message-Id: <8307080845.AA16294@UCBVAX.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.ARPA (3.346/3.33)
+       id AA16294; 8 Jul 83 01:45:43 PDT (Fri)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA01687; 8 Jul 83 01:46:25 PDT (Fri)
+To: franz-friends@BERKELEY.ARPA
+Via:  UPenn; 8 Jul 83 3:07-EDT
+Status: O
+
+Does anyone have a version of Eliza that runs under Franz Lisp?
+
+From layer  Fri Jul  8 18:04:10 1983
+Date:  8 Jul 1983 1804-PDT (Friday)
+From: layer (Kevin Layer)
+Subject: lisp opus 38.69
+Message-Id: <7031.30.426560643@ucbkim>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA07142; 8 Jul 83 18:04:10 PDT (Fri)
+Phone: (415) 652-2405
+To: local-lisp
+Cc: layer
+Status: O
+
+  'setf' now knows about 'nthelem', and there are two new functions:
+
+       (readdir 's_direct)
+               returns a list of the contents of the directory s_direct.
+
+       (dirp 's_name)
+               returns s_name if s_name is a directory.  This doesn't
+               insure that you can read the directory, though (only
+               uses stat(2)).
+
+                                       Kevin
+
+From layer  Fri Jul  8 20:57:13 1983
+Date:  8 Jul 1983 2057-PDT (Friday)
+From: layer (Kevin Layer)
+Subject: new function readdir
+Message-Id: <465.30.426571029@ucbkim>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA00480; 8 Jul 83 20:57:13 PDT (Fri)
+Phone: (415) 652-2405
+To: local-lisp
+Fcc: record
+Status: O
+
+  The function 'readdir' and 'dirp' should not be relied on yet, since
+they are provisional, because they are implemented with C library
+functions only available on 4.1+ systems.
+
+       Kevin
+
+From Pwh%GaTech.GATech@UDel-Relay  Tue Jul 12 18:08:46 1983
+Date:     11 Jul 83 20:36:32-EDT (Mon)
+From: <pwh.gatech@UDel-Relay>
+Subject:  Franz flavors?
+Return-Path: <Pwh%GaTech.GATech@UDel-Relay>
+Message-Id: <8307130107.AA03336@UCBVAX.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.ARPA (3.346/3.33)
+       id AA03336; 12 Jul 83 18:07:40 PDT (Tue)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA20140; 12 Jul 83 18:08:46 PDT (Tue)
+To: franz-friends@BERKELEY.ARPA
+Cc: jlk.Gatech@UDel-Relay
+Via:  GATech; 12 Jul 83 2:43-EDT
+Status: O
+
+We at Ga Tech (ai group working under prof Janet Kolodner) have just gotten our
+long awaited Symbolics Lisp Machine up and running and are trying to establish
+some measure of compatability between Franz and Zeta Lisp (as appropriate).
+Janet seems to recall some mention of a flavor package for Franz. Is this
+Berkley based or can anyone provide some clues as to where to check next?
+
+Also, when is the next release of Franz scheduled and what features will it
+incorporate?
+
+If the flavor package is non-existent, we will probably be forced to develop
+one here and will, of course, be glad to pass anything useful along.
+
+phil hutto
+
+From narain@rand-unix  Tue Jul 12 20:10:42 1983
+Date: Tuesday, 12 Jul 1983 19:49-PDT
+From: narain@rand-unix
+Subject: Re:  Franz flavors?
+Message-Id: <8307130309.AA05908@UCBVAX.ARPA>
+Received: from rand-unix (rand-unix.ARPA) by UCBVAX.ARPA (3.346/3.33)
+       id AA05908; 12 Jul 83 20:09:41 PDT (Tue)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA21387; 12 Jul 83 20:10:42 PDT (Tue)
+To: <pwh.gatech@UDEL-RELAY>
+Cc: franz-friends@BERKELEY.ARPA, jlk.Gatech@UDEL-RELAY
+In-Reply-To: Your message of     11 Jul 83 20:36:32-EDT (Mon).
+             <8307130107.AA03336@UCBVAX.ARPA>
+Status: O
+
+
+We at Rand are interested in developing a set of guidelines for writing
+code that will be compatible with each of Zeta- Franz- and PSL Lisps. I
+would be grateful if you could tell us of what your experiences have been with
+making Franzlisp code work on the Symbolics machine. We would gladly share
+our own with you if you wish; incidentally we also have an IJCAI paper on a
+related issue.
+
+-- Sanjai Narain
+
+From liz.umcp-cs@UDel-Relay  Wed Jul 13 00:55:26 1983
+Date:     13 Jul 83 03:09:39 EDT  (Wed)
+From: Liz Allen <liz.umcp-cs@UDel-Relay>
+Subject:  Re:  Franz flavors?
+Return-Path: <liz.umcp-cs@UDel-Relay>
+Message-Id: <8307130754.AA10367@UCBVAX.ARPA>
+Received: from udel-relay.ARPA by UCBVAX.ARPA (3.346/3.33)
+       id AA10367; 13 Jul 83 00:54:32 PDT (Wed)
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA24477; 13 Jul 83 00:55:26 PDT (Wed)
+To: pwh.gatech@UDel-Relay, franz-friends@BERKELEY.ARPA
+Cc: jlk.Gatech@UDel-Relay
+Via:  UMCP-CS; 13 Jul 83 3:23-EDT
+Status: O
+
+Here at the Univ of Maryland, we do have an implementation of
+flavors in Franz Lisp and have used it successfully in several
+large systems.  It doesn't contain all the features of the Lisp
+Machine Flavors, but it does implement all the major ones.  It is
+also different in a few ways that are necessitated by the limitations
+of Franz Lisp (shallow binding without invisible pointers or true
+closures -- though closures may be in the very newest versions of
+Franz -- we have opus 38.26).  The package uses a hashing scheme
+for looking up methods, and the function <- which is used to send
+a message to an object is written in C.  Together, this makes it
+an efficient implementation.
+
+We are currently working on a new policy for distributing flavors,
+our other lisp packages and our window package.  When we have worked
+it out, I will announce the details here.
+
+                               -Liz
+
+From @MIT-MC:mdm@cmu-ri-isl  Thu Jul 14 11:07:57 1983
+Date: 14 Jul 1983 14:03:01-EDT
+From: Malcolm.McRoberts@CMU-RI-ISL
+Subject: random numbers
+Message-Id: <8307141806.AA05735@UCBVAX.ARPA>
+Received: from MIT-MC (mit-mc.ARPA) by UCBVAX.ARPA (3.347/3.35)
+       id AA05735; Thu, 14 Jul 83 11:06:45 PDT
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA13687; 14 Jul 83 11:07:57 PDT (Thu)
+Apparently-To: <franz-friends@UCB-VAX>
+Status: O
+
+I am interested in obtaining a GOOD random number generator that is callable
+from Franz.  My only real requirements are that it accept a seed (so that I
+can duplicate the same series), is fairly good (try doing several (random
+4)'s in Franz and see what you get), and is of intermediate speed.  If you
+know of such an animal please send me mail telling me how to get it.
+                                                       thanks
+
+
+From kanderso@bbn-vax  Thu Jul 14 12:49:58 1983
+Date: 14 Jul 1983 15:47:19 EDT (Thursday)
+From: Ken Anderson <kanderso@bbn-vax>
+Subject: Random numbers
+Message-Id: <8307141948.AA06936@UCBVAX.ARPA>
+Received: from bbn-vax (bbn-vax.ARPA) by UCBVAX.ARPA (3.347/3.35)
+       id AA06936; Thu, 14 Jul 83 12:48:49 PDT
+Received: from UCBVAX.ARPA by UCBKIM.ARPA (3.340/3.5)
+       id AA15607; 14 Jul 83 12:49:58 PDT (Thu)
+To: franz-friends@BERKELEY.ARPA
+Cc: Malcolm.McRoberts@CMU-RI-ISL
+Status: O
+
+Here is a random number generator i use.  It seems to work fairly well, but i have
+not looked to closely at the statistics.  Since it will occasionally require
+bignums, it is probably not the fastest either.  I was just looking for something
+that was likely to be portable between LISP's.
+I would be very interested in hearing your evaluation of it.
+
+k
+
+;;; RANDOM NUMBERS
+(declare (macros t))
+(include math.h)
+
+(defvar $uniform-a 16807) ; = 7^5
+(defvar $mersenne-prime 2147483647) ; = 2^31 - 1
+(defvar $mersenne-prime-1 (- $mersenne-prime 1))
+
+(defmacro with-seed (s-newseed . body)
+  ; evaluates body with the seed of the random numbers set to s-newseed.
+  ; the value of s-newseed is updated.  Thus this is a way of
+  ; Keepining several sequences of random numbers with their own seeds
+  `(let (($uniform-seed ,s-newseed))
+       (prog1 (progn ,@body) 
+              (setq ,s-newseed $uniform-seed))))
+
+(defun uniform-basic (previous-fixnum)
+  ; -> a fixnum 0 < fixnum < 2^31 - 1
+  ; Repeated calls will generate fixnums in the range
+  ; 1 -> 2^31 - 2.
+
+  ; The basic idea is new = A^k * old (mod p)
+  ; where A is a primitive root of p, k is not a factor of  p-1
+  ; and p is a large prime.
+
+  ; This is a good random number generator but is not be the fastest!
+  ; On FRANZ LISP, and LISP MACHINE it will require bignums since
+  ; (* $uniform-a previous-fixnum) can have 46 bits in it. Also the remainder
+  ; can be done more efficiently.
+  ; See: Linus Schrage, A More Portable Fortran Random Number Generator,
+  ;      ACM Trans. Math. Soft., V5, No. 2, p 132-138, 1979.
+  (remainder (*$ $uniform-a previous-fixnum) $mersenne-prime))
+
+(defvar $uniform-seed 53) ; 0 < fixnum < $mersenne-prime-1
+
+(defun uniform ()
+  ; -> the next uniform random number in the sequence
+  ; To have your own sequence, rebind $uniform-seed.
+  (setq $uniform-seed (uniform-basic $uniform-seed)))
+
+(defun uniform-between (low-num high-num)
+  ; -> a uniform random  number, x, low-num <= x <= high-num
+  ; If low-num and high-num are fixnums, a fixnum is returned.
+  (cond ((not (and (fixp low-num) (fixp high-num)))
+        (+$ low-num (*$ (//$ (uniform) (float $mersenne-prime-1))
+                      (-$ high-num low-num))))
+       (t (+ low-num (// (uniform)
+                         (// $mersenne-prime-1 (max 1 (- high-num low-num -1))))))))
+
+(defun gaussian-random-1 ()
+  ; -> a gaussian random variable with mean 0.0 and
+  ; standard deviation 1.0.
+  ; Good tails.
+  (*$ (sqrt (*$ -2.0 (log (uniform-between 0.0 1.0))))
+     (sin (*$ $2pi (uniform-between 0.0 1.0)))))
+
+(defun gaussian-random (mean standard-deviation)
+  (+$ mean (*$ (gaussian-random-1) standard-deviation)))
+
+;;(defun gaussian (x)
+;;  (* (sqrt $2pi) 
+;;     (exp (minus (// (square x) 2.0)))))
+
+(defun random-yes-no (fraction-yes)
+    (<= (uniform-between 0.0 1.0) fraction-yes))
+
+
+From layer  Sat Jul 30 15:46:42 1983
+Date: 30 Jul 1983 1546-PDT (Saturday)
+From: layer (Kevin Layer)
+Subject: liszt opus 8.33
+Message-Id: <19472.30.428453197@ucbkim>
+Received: by UCBKIM.ARPA (3.340/3.5)
+       id AA19498; 30 Jul 83 15:46:42 PDT (Sat)
+Phone: (415) 652-2405
+To: local-lisp
+Status: O
+
+  Vset is now open coded.  There should be no visible change in the
+behaviour of vectors, except in speed (greater, that is), and 
+vsize-{byte,word} work properly now.
+
+  Bugs to me.
+
+       Kevin
+
+From jkf  Mon Aug  1 14:41:28 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA03743; Mon, 1 Aug 83 14:41:28 PDT
+Date: Mon, 1 Aug 83 14:41:28 PDT
+From: jkf (John Foderaro)
+Message-Id: <8308012141.AA03743@ucbkim.ARPA>
+To: local-lisp
+Subject: defstruct
+Status: O
+
+  defstruct now understands two more types of structures:
+       :vector
+       :named-vector
+
+  A named vector has the defstruct structure name on the vector property
+list, thus an instance of the foo structure would print as 'foo[8]'.
+
+
+  :named-vector is now the default structure type (instead of :hunk).
+
+
+
+
+From jkf  Tue Aug  2 15:20:04 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA26686; Tue, 2 Aug 83 15:20:04 PDT
+Date: Tue, 2 Aug 83 15:20:04 PDT
+From: jkf (John Foderaro)
+Message-Id: <8308022220.AA26686@ucbkim.ARPA>
+To: local-lisp
+Subject: lisp opus 38.70
+Status: RO
+
+  When a vector is printed, the size in square brackets will be the number
+of entries (not the number of bytes).  The size printed for vectori
+objects will continue to be the number of bytes.
+
+  Also, if the property of a vector is a list with the car being a non nil
+symbol, and if that list doesn't have a print property, then that
+symbol will be printed rather than 'vector' or 'vectori'.
+
+
+
+From layer  Thu Aug  4 02:10:12 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA11660; Thu, 4 Aug 83 02:10:12 PDT
+From: layer (Kevin Layer)
+Phone: (415) 652-2405
+Date:  4 Aug 1983 0210-PDT (Thursday)
+Message-Id: <11649.30.428836207@ucbkim>
+To: local-lisp
+Subject: liszt opus 8.34
+Status: RO
+
+  I just installed a new compiler.  For the vax, there shouldn't be
+any visible changes, though a couple of vector bugs were fixed.  For
+the 68000, the vector access functions are now open coded, and the
+new one was installed on mike, rob, and chip in /usr/ucb.
+
+       Kevin
+
+From FRD@SU-AI  Fri Aug  5 15:57:17 1983
+Received: from UCBVAX.ARPA by ucbkim.ARPA (4.2/4.2)
+       id AA10610; Fri, 5 Aug 83 15:57:17 PDT
+Received: from SU-AI.ARPA by UCBVAX.ARPA (3.347/3.35)
+       id AA10357; Fri, 5 Aug 83 15:54:22 PDT
+Message-Id: <8308052254.AA10357@UCBVAX.ARPA>
+Date: 05 Aug 83  1353 PDT
+From: Fred Lakin <FRD@SU-AI>
+Subject: Franz & SUNs  
+To: franz-friends@BERKELEY
+Status: RO
+
+I am interested in connectons between Franz and SUN workstations.
+Like how far along is Franz on the SUN?  Is there some package
+which allows Franz on a VAX to use a SUN as a display device?
+
+Any info on this matter would be appreciated.
+Thnaks, Fred Lakin
+
+
+From tektronix!ogcvax!metheus!tombl  Sat Aug  6 09:49:57 1983
+Received: from UCBVAX.ARPA by ucbkim.ARPA (4.2/4.2)
+       id AA21229; Sat, 6 Aug 83 09:49:57 PDT
+Received: by UCBVAX.ARPA (3.347/3.35)
+       id AA13549; Sat, 6 Aug 83 09:40:11 PDT
+Message-Id: <8308061640.AA13549@UCBVAX.ARPA>
+From: ogcvax!metheus!tombl
+To: ogcvax!tektronix!ucbvax!franz-friends
+Cc: ogcvax!tektronix!ucbvax!sklower
+Received: from ogcvax.uucp by tektronix ; 5 Aug 83 20:51:03 PDT
+Subject: bug in Opus 38.66
+Date: Fri Aug  5 20:46:56 1983
+Status: O
+
+
+A bug present in previous versions is also present in 38.66 of Franz.
+cfasl fails (in most cases) to close the file it reads from.
+Consequently, mysterious events occur when the maximum number of open
+file descriptors is reached.
+
+The fix is made in the file ffasl.c. "close(fildes)" should be
+prepended to the two return sequences from (the Unix code for)
+Lcfasl:
+
+------------------------------------------------------------------
+Old:   146c146
+       <               {Restorestack(); return(nil);}
+       ---
+Fixed: >               {close(fildes); Restorestack(); return(nil);}
+       149a150
+       >       close(fildes);
+------------------------------------------------------------------
+
+
+       Tom Blenko
+       Metheus Corp.
+       ucbvax!tektronix!ogcvax!metheus!tombl
+       allegra!ogcvax!metheus!tombl
+
+
+
+From FRD@SU-AI  Sun Aug  7 12:34:43 1983
+Received: from UCBVAX.ARPA by ucbkim.ARPA (4.2/4.2)
+       id AA10610; Fri, 5 Aug 83 15:57:17 PDT
+Received: from SU-AI.ARPA by UCBVAX.ARPA (3.347/3.35)
+       id AA10357; Fri, 5 Aug 83 15:54:22 PDT
+Message-Id: <8308052254.AA10357@UCBVAX.ARPA>
+Date: 05 Aug 83  1353 PDT
+From: Fred Lakin <FRD@SU-AI>
+Subject: Franz & SUNs  
+To: franz-friends@BERKELEY
+Status: O
+
+I am interested in connectons between Franz and SUN workstations.
+Like how far along is Franz on the SUN?  Is there some package
+which allows Franz on a VAX to use a SUN as a display device?
+
+Any info on this matter would be appreciated.
+Thnaks, Fred Lakin
+
+
+From jkf  Mon Aug  8 09:06:49 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA06584; Mon, 8 Aug 83 09:06:49 PDT
+Date: Mon, 8 Aug 83 09:06:49 PDT
+From: jkf (John Foderaro)
+Message-Id: <8308081606.AA06584@ucbkim.ARPA>
+To: local-lisp
+Subject: opus 38.72
+Status: O
+
+  A bug was fixed in defmacro which caused the &protect option and
+displace-macros to interact poorly.
+
+
+
+From jkf  Fri Aug 12 22:11:13 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA25610; Fri, 12 Aug 83 22:11:13 PDT
+Date: Fri, 12 Aug 83 22:11:13 PDT
+From: jkf (John Foderaro)
+Message-Id: <8308130511.AA25610@ucbkim.ARPA>
+To: local-lisp
+Subject: opus 38.73
+Status: O
+
+ 'equal' will now compare all types of vectors for equality.
+
+ 'copy' will now copy all types of vectors.
+
+
+
+From layer  Mon Aug 15 20:03:53 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA03597; Mon, 15 Aug 83 20:03:53 PDT
+From: layer (Kevin Layer)
+Phone: (415) 652-2405
+Date: 15 Aug 1983 2003-PDT (Monday)
+Message-Id: <3556.30.429851029@ucbkim>
+To: local-lisp
+Subject: liszt opus 8.35
+Fcc: record
+Status: RO
+
+  Several things have changed:
+
+1) Bugs in the open coding of vectors have been fixed.
+
+2) Minor re-organization of the compiler source code.
+
+3) The routine to determine whether or not tail merging is
+   possible underwent major modification.
+
+4) Lexpr's are compiled differently, or rather the way lexpr args
+   are accessed has changed.  For those that want to know, here is
+   the nitty gritty:
+
+     Consider a the following lexpr: (defun test nargs ...).
+     The arguments to the lexpr are stacked on the name stack
+     (low to high number), and then nargs is stacked.  The user
+     is allowed to change the binding of 'nargs' to anything
+     he likes, so we have to have another way to access the arguments
+     on the name stack (i.e., other than an offset from nargs).
+     Before, a pointer to the argument base was pushed on the 
+     C stack, so that indexing could be done from there.
+     The addressing modes used to do this are not available
+     on the MC68000 (something like *n(fp)[Rx]), so now
+     nargs is pushed on the name stack twice, and the location
+     of an argument can be easily calculated as an offset from nargs.
+
+In short, lots of thing changed.  The SUN's should be updated
+in the next couple of days (after I test it out).  Bugs to me...
+
+       Kevin
+
+From jkf  Mon Aug 15 23:11:08 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA05928; Mon, 15 Aug 83 23:11:08 PDT
+Date: Mon, 15 Aug 83 23:11:08 PDT
+From: jkf (John Foderaro)
+Message-Id: <8308160611.AA05928@ucbkim.ARPA>
+To: local-lisp
+Subject:  opus 38.74
+Status: O
+
+
+  If a vector has a 'unique' property on it's property list, then it will
+not be copied by 'copy'.
+
+  'untrace' will now autoload /usr/lib/lisp/trace.
+
+  A number of functions and macros were contributed by the bair group:
+
+
+
+
+
+
+
+(<= 'fx_arg1 'fx_arg2 ...)
+(<=& 'x_arg1 'x_arg2)
+
+     RETURNS: t iff (> 'fx_arg1 'fx_arg2)  [or  (>&  'x_arg1
+              'x_arg2)]  is nil, otherwise nil.  The general
+              function, <=, can take  more  than  two  argu-
+              ments.
+
+(>= 'fx_arg1 'fx_arg2)
+(>=& 'x_arg1 'x_arg2)
+
+     RETURNS: t  iff  (<  'fx_arg1  'fx_arg2  ...)  [or  (<&
+              'x_arg1 'x_arg2)] is nil, otherwise nil.
+
+     NOTE: The general function, >=, can take more than  two
+           arguments.
+
+(litatom 'g_arg)
+
+     RETURNS: t iff g_arg is an atom, but not a number.
+
+(nequal 'g_x 'g_y)
+
+     RETURNS: t iff g_x is not equal to g_y, otherwise nil.
+
+(lineread [['p_port] ['s_flag]])
+
+     RETURNS: a list consisting of s-expressions on  a  line
+              from  the  port p_port (or piport if p_port is
+              not given).  If an s-expression (e.g., a list)
+              takes more than one line, or a line terminates
+              in a space or  tab,  then  lineread  continues
+              reading until an expression ends at the end of
+              a line.
+
+     NOTE: If s_flag is t, then if the first character on  a
+           line  is  a  newline, lineread performs a tyi and
+           returns nil.  If s_flag is nil  or  not  present,
+           lineread  does  a  read  skipping  over any blank
+           lines to make sure that an s-expression is  actu-
+           ally read.
+
+     SIDE EFFECT: lineread uses  read,  advancing  the  port
+                  character pointer.
+
+
+
+
+
+
+
+
+\e9
+
+\e9
+
+
+
+
+
+
+
+
+
+
+(defv g_arg1 g_arg2)
+
+     EQUIVALENT TO: (set g_arg1 g_arg2)
+
+(pp-form 'g_form ['p_port] ['n_lmar])
+
+     RETURNS: nil
+
+     SIDE EFFECT: g_form  is  pretty-printed  to  the   port
+                  p_port (or poport if p_port is not given).
+                  If  pp-form  is  also  supplied  with   an
+                  integer  (n_lmar),  that  integer  will be
+                  used as a left margin setting  (0  is  the
+                  default).   This is the  function which pp
+                  uses (n_lmar = 0). pp-form does  not  look
+                  for  function  definitions  or  values  of
+                  variables, it just prints out the form  it
+                  is given.
+
+     NOTE: This is useful as a top-level-printer, c.f.  top-
+           level in Chapter 6.
+
+(sload 's_file1 ...)
+
+     SIDE EFFECT: The files named are opened for reading and
+                  each form is read, optionally printed, and
+                  evaluated.
+
+     NOTE: What sload prints is controlled  by  the  special
+           atom  $sldprint.   If  $sldprint  is t (default),
+           then if a form  is  recognizable  as  a  function
+           definition,  only  the  function name is printed,
+           otherwise  the  whole  form   is   printed.    If
+           $sldprint is eq to value, then the result of each
+           form's evaluation will also be printed.  Printing
+           the  forms'  values  can be controlled by setting
+           sload-print equal to the name of the function  to
+           be  called.   sload recognizes named functions by
+           looking at  the  sloadprintarg  property  of  the
+           function  name.   The  value of the sloadprintarg
+           property should be the  argument  number  of  the
+           function name.  For the standard Franz Lisp func-
+           tions, the properties are already set.
+
+     EXAMPLE: (defprop def 1 sloadprintarg)   ; This is  the
+              default--declaring that
+                                              ; the name  of
+              the function definition is the
+                                              ; first  argu-
+              ment.
+
+
+\e9
+
+\e9
+
+
+
+
+
+
+
+
+
+
+          The functions described below are  an  alternative
+     to  the  gensym facility.  They generate new symbols by
+     attaching counter numbers to the ends of  the  symbols'
+     names.   An  example  follows  of how the functions are
+     used.
+
+
+    ____________________________________________________
+
+    -> (initsym joe (john 5))       ; initializing new symbol counters
+    (joe0 john5)
+    -> (newsym john)                ; create a new symbol
+    john6
+    -> (newsym chuck)               ; symbol need not be initsym'ed
+    chuck0
+    -> (oldsym john)                ; get current symbol
+    john6
+    -> (allsym john)                ; get all symbols between 0 and counter
+    (john0 john1 john2 john3 john4 john5 john6)
+    -> (allsym (john 5))            ; get all symbols between 5 and counter
+    (john5 john6)
+    -> (remsym joe (john 4))        ; remob all interned symbols
+                                    ; associated with joe and from
+                                    ; john4 to the current john
+                                    ; symbol--returns symbols with symbol counters
+                                    ; before doing remsym
+    (joe0 john6)
+    -> (symstat joe john)
+    ((joe nil) (john 3))
+    ____________________________________________________
+
+
+
+
+(initsym g_arg1 ...)
+
+     WHERE:   g_argi is a  list  (n_counteri  s_argi)  or  a
+              string  s_argi  (which  is  equivalent  to  (0
+              s_argi)).
+
+     RETURNS: a list of interned identifiers using the  sym-
+              bol  counters  n_counteri, i.e., the result of
+              concatenating s_argi to n_counteri.
+
+     EXAMPLE: (initsym joe (john 5)) ==> (joe0 john5)
+
+     NOTE: See also newsym, oldsym, allsym, remsym, and sym-
+           stat functions.
+
+
+
+
+\e9
+
+\e9
+
+
+
+
+
+
+
+
+
+
+(newsym s_arg)
+
+     RETURNS: an interned identifier formed by concatenating
+              the  name  s_arg  to  the  symbol  counter for
+              s_arg.  The symbol counter is  stored  on  the
+              property list of s_arg under symctr.  If there
+              is no counter, a counter  of  0  is  used  and
+              added  to  the  property list.  Thus, a symbol
+              need not be initsymed.
+
+     EXAMPLE: (initsym joe (john5)) ==> (joe0 john5)
+              (newsym john) ==> john6
+              (newsym joe) ==> joe1
+
+     NOTE: See also initsym,  oldsym,  allsym,  remsym,  and
+           symstat functions.
+
+(oldsym s_arg)
+
+     RETURNS: the  identifier  using  the   current   symbol
+              counter  for s_arg, rather than creating a new
+              identifier.  If no symbol counter  exists  for
+              s_arg, then s_arg is returned.
+
+     NOTE: See also initsym,  newsym,  allsym,  remsym,  and
+           symstat functions.
+
+(allsym g_arg)
+
+     WHERE:   g_arg is a list (s_arg n_counter) or a  string
+              s_arg (equivalent to (s_arg 0)).
+
+     RETURNS: a list of all the created identifiers  between
+              n_counter  and  the current symbol counter for
+              s_arg.
+
+     EXAMPLE: (allsym john) ==> (john0 john1 john2)
+
+     NOTE: See also initsym,  newsym,  oldsym,  remsym,  and
+           symstat functions.
+
+(remsym g_arg1 ...)
+
+     WHERE:   g_argi is a  list  (s_argi  n_counteri)  or  a
+              string  s_argi (which is equivalent to (s_argi
+              0)).
+
+     RETURNS: a list of symbols s_argi with the current sym-
+              bol counters.
+
+     SIDE EFFECT: remsym remob's all the created identifiers
+                  between   zero   and  the  current  symbol
+                  counter for s_argi.
+
+
+
+
+
+
+
+
+
+
+
+
+
+     NOTE: See also initsym, newsym oldsym, allsym, and sym-
+           stat functions.
+
+(symstat s_arg1 ...)
+
+     RETURNS: a list of pairs consisting of (s_argi symctri)
+              where   symctri  is  s_argi's  current  symbol
+              counter.
+
+     NOTE: See also initsym,  newsym,  oldsym,  allsym,  and
+           remsym functions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+\e9
+
+\e9
+
+
+
+
+
+
+From jkf  Thu Aug 18 19:25:45 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA09885; Thu, 18 Aug 83 19:25:45 PDT
+Date: Thu, 18 Aug 83 19:25:45 PDT
+From: jkf (John Foderaro)
+Message-Id: <8308190225.AA09885@ucbkim.ARPA>
+To: local-lisp
+Subject: opus 38.75
+
+  evalhook and funcallhook can now be executed without setting (*rset t)
+and (sstatus evalhook t).   Although they can be executed, they won't
+have any effect unless and until (*rset t) and (sstatus evalhook t) are
+done.
+  The reason for this change is that now one can turn off stepping
+by (sstatus evalhook nil) and then continue the evaluation with
+evalhook and funcallhook.
+
+  Those who use the new top-level 'tpl' will notice a few new commands
+dealing with stepping when you type '?help'.   These new commands
+are ?step, ?soff, and ?sc. Details of the commands are available
+using the help mechanism (e.g. '?help step').
+
+
+
+
+From jkf  Fri Aug 19 13:54:26 1983
+Received: by ucbkim.ARPA (4.2/4.2)
+       id AA20017; Fri, 19 Aug 83 13:54:26 PDT
+Date: Fri, 19 Aug 83 13:54:26 PDT
+From: jkf (John Foderaro)
+Message-Id: <8308192054.AA20017@ucbkim.ARPA>
+To: local-lisp
+Subject: liszt 8.36
+
+ The compiler will now compile the form
+       (*no-macroexpand* <form>)
+ in a special way: if <form> is a function call, e.g. (name arg1 ...),
+ then any macro properties of 'name' will be ignored for this
+ invocation.  This permits one to write macros which attempt
+ an optimization, and if that fails, then call the standard
+ function.  *no-macroexpand* is not a function that can be called,
+ thus forms with *no-macroexpand* are likely to be 'cmacros'.
+ Here is an example:
+
+   (defcmacro length (x &protect (x))
+       `(if (null ,x)
+          then 0
+        elseif (null (cdr ,x))
+         then 1
+        else (*no-macroexpand* (length ,x))))
+
+
+ [in case you are wondering, the `&protect (x)' means that
+  should the actual argument to 'length' be a non atom, defcmacro
+  will lambda bind the value, insuring that it is only evaluated
+  once]
+
+
+From layer  Wed Aug 24 22:18:34 1983
+Received: by ucbkim.ARPA (4.6/4.2)
+       id AA12256; Wed, 24 Aug 83 22:18:34 PDT
+From: layer (Kevin Layer)
+Phone: (415) 652-2405
+Date: 24 Aug 1983 2218-PDT (Wednesday)
+Message-Id: <12219.30.430636709@ucbkim>
+To: local-lisp
+Subject: liszt on kim
+
+  The liszt that I installed on kim yesterday, compiled eq's wrong
+in some rare cases.  I installed a new one this evening that fixes
+this, but if you compiled any programs with the bad one, you might
+consider re-compiling them...
+
+       Kevin
+
+From fateman  Thu Aug 25 13:58:59 1983
+Received: by ucbkim.ARPA (4.6/4.2)
+       id AA21033; Thu, 25 Aug 83 13:58:59 PDT
+Date: Thu, 25 Aug 83 13:58:59 PDT
+From: fateman (Richard Fateman)
+Message-Id: <8308252058.AA21033@ucbkim.ARPA>
+To: local-lisp
+
+I have a copy of the latest Common Lisp manual... the Excelsior Edition.
+
+From patel@UCLA-LOCUS  Tue Aug 30 21:58:38 1983
+Received: from ucbvax.ARPA by ucbkim.ARPA (4.6/4.2)
+       id AA29417; Tue, 30 Aug 83 21:58:38 PDT
+Received: from ucla-locus (ucla-locus.ARPA) by ucbvax.ARPA (4.8/4.4)
+       id AA06203; Tue, 30 Aug 83 21:50:26 PDT
+Message-Id: <8308310450.AA06203@ucbvax.ARPA>
+Date:           Tue, 30 Aug 83 21:44:13 PDT
+From: Dorab Patel <patel@UCLA-LOCUS>
+To: franz-friends@BERKELEY
+Subject:        bug fix for 'insert' in opus 38.50
+
+The function 'insert' in Opus 38.50 does not perform as advertised in 
+the manual if the last argument is non-nil (i.e. if no duplicates are allowed.
+It still insists on putting the duplicate element into the list. The
+fix is in /usr/lib/lisp/common2.l. Just change the default setting
+of the 'comparefn' to that given below instead of 
+(function alphalessp). Here is an excerpt from the modified file.
+
+
+  [.....]
+(def insert
+     (lambda (x l comparefn nodups)
+      (cond ((null l) (list x))
+            ((atom l)
+             (error "an atom, can't be inserted into" l))
+            (t (cond
+                ((null comparefn) (setq comparefn 
+                                       (function
+                                        (lambda (x y) 
+                                                (or (alphalessp x y) 
+                                                    (equal x y)))))))
+               (prog (l1 n n1 y)
+                     (setq l1 l)
+                     (setq n (length l))
+                a    (setq n1 (/ (add1 n) 2))
+                     (setq y (Cnth l1 n1))
+                    [..........]
+
+From jkf  Sun Sep  4 09:59:01 1983
+Received: by ucbkim.ARPA (4.6/4.2)
+       id AA03721; Sun, 4 Sep 83 09:59:01 PDT
+Date: Sun, 4 Sep 83 09:59:01 PDT
+From: jkf (John Foderaro)
+Message-Id: <8309041659.AA03721@ucbkim.ARPA>
+To: local-lisp
+Subject: opus 38.77
+
+  The 'error' function used to print its arguments and then call 'err' to
+cause the familar 'call to err' error.  The problem with this is that
+even if you wrap your compuatation with (errset ... nil), the error message
+will still be printed.   In opus 38.77, this problem has been fixed.
+
+A new function was added:
+       (err-with-message 'st_message ['g_value])
+ This causes an error to be signaled with the given message.   The message
+will only be printed if an '(errset ... nil)' isn't being executed.
+Normally nil is returned from an errset if an error occured.  If you provide
+g_value, then it will be returned from the errset.
+[Not surprisingly, 'error' now uses 'err-with-message']
+
+
+Also, 'error' now takes any number of arguments.  In concatenates them,
+separated by spaces, and this is the error message passed to
+err-with-message.
+
+
+
+
+From narain@rand-unix  Fri Sep  9 13:32:24 1983
+Received: from ucbvax.ARPA by ucbkim.ARPA (4.6/4.2)
+       id AA16481; Fri, 9 Sep 83 13:32:24 PDT
+Received: from rand-unix (rand-unix.ARPA) by ucbvax.ARPA (4.12/4.7)
+       id AA11010; Fri, 9 Sep 83 13:31:58 PDT
+Message-Id: <8309092031.AA11010@ucbvax.ARPA>
+Date: Friday,  9 Sep 1983 10:55-PDT
+To: franz-friends@BERKELEY
+Cc: narain@rand-unix
+Subject: Franzlisp Question
+From: narain@rand-unix
+
+
+Hello all:
+
+I would be grateful if you could answer another question regarding Franzlisp.
+How does one make Franzlisp continue from an error? For example when Lisp
+gives an error message like "x unbound variable", is it possible to
+bind x to a value and make Lisp continue from that point? Right now we have
+to start over again and it is very time consuming.
+
+-- Sanjai
+
+From AUSTIN@DEC-MARLBORO.ARPA  Fri Sep  9 13:46:45 1983
+Received: from ucbvax.ARPA by ucbkim.ARPA (4.6/4.2)
+       id AA16843; Fri, 9 Sep 83 13:46:45 PDT
+Received: from DEC-MARLBORO.ARPA by ucbvax.ARPA (4.12/4.7)
+       id AA11248; Fri, 9 Sep 83 13:46:26 PDT
+Date: 9 Sep 1983 1427-EDT
+From: AUSTIN@DEC-MARLBORO
+To: FRANZ-FRIENDS@BERKELEY
+Subject: LIST MEMBERSHIP
+Message-Id: <"MS10(2124)+GLXLIB1(1136)" 11950297972.20.647.3882 at DEC-MARLBORO>
+
+PLEASE ADD ME TO FRANZ-FRIENDS@BERKELEY DISTRIBUTION.
+
+MY NAME IS TOM AUSTIN AND MY NETWORK ADDRESS IS AUSTIN@DEC-MARLBORO.
+
+THANKS!
+   --------
+
+From jkf  Sat Sep 10 12:34:14 1983
+Received: by ucbkim.ARPA (4.6/4.2)
+       id AA28421; Sat, 10 Sep 83 12:34:14 PDT
+Date: Sat, 10 Sep 83 12:34:14 PDT
+From: jkf (John Foderaro)
+Message-Id: <8309101934.AA28421@ucbkim.ARPA>
+To: local-lisp
+Subject: opus 38.78
+
+ The new functions contributed by the bair group dealing with symbol
+creation have been changed from fexprs to exprs (lambdas) and lexprs.
+
+The new documentation follows:
+
+
+
+
+
+
+
+     The functions described below are an alternative to the
+gensym  facility.   They  generate  new symbols by attaching
+counter numbers to the ends of the symbols' names.  An exam-
+ple follows of how the functions are used.
+
+
+    ____________________________________________________
+
+    -> (initsym 'joe '(john 5))     ; initializing new symbol counters
+    (joe0 john5)
+    -> (newsym 'john)               ; create a new symbol
+    john6
+    -> (newsym 'chuck)              ; symbol need not be initsym'ed
+    chuck0
+    -> (oldsym 'john)               ; get current symbol
+    john6
+    -> (allsym 'john)               ; get all symbols between 0 and counter
+    (john0 john1 john2 john3 john4 john5 john6)
+    -> (allsym '(john 5))           ; get all symbols between 5 and counter
+    (john5 john6)
+    -> (remsym 'joe '(john 4))      ; remob all interned symbols
+                                    ; associated with joe and from
+                                    ; john4 to the current john
+                                    ; symbol--returns symbols with symbol counters
+                                    ; before doing remsym
+    (joe0 john6)
+    -> (symstat 'joe 'john)
+    ((joe nil) (john 3))
+    ____________________________________________________
+
+
+
+
+(initsym 'g_arg1 ...)
+
+     WHERE:   g_argi is a  list  (n_counteri  s_argi)  or  a
+              string  s_argi  (which  is  equivalent  to  (0
+              s_argi)).
+
+     RETURNS: a list of interned identifiers using the  sym-
+              bol  counters  n_counteri, i.e., the result of
+              concatenating s_argi to n_counteri.
+
+     EXAMPLE: (initsym 'joe '(john 5)) ==> (joe0 john5)
+
+     NOTE: See also newsym, oldsym, allsym, remsym, and sym-
+           stat functions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+(newsym 's_arg)
+
+     RETURNS: an interned identifier formed by concatenating
+              the  name  s_arg  to  the  symbol  counter for
+              s_arg.  The symbol counter is  stored  on  the
+              property list of s_arg under symctr.  If there
+              is no counter, a counter  of  0  is  used  and
+              added  to  the  property list.  Thus, a symbol
+              need not be initsymed.
+
+     EXAMPLE: (initsym 'joe '(john5)) ==> (joe0 john5)
+              (newsym 'john) ==> john6
+              (newsym 'joe) ==> joe1
+
+     NOTE: See also initsym,  oldsym,  allsym,  remsym,  and
+           symstat functions.
+
+(oldsym 's_arg)
+
+     RETURNS: the  identifier  using  the   current   symbol
+              counter  for s_arg, rather than creating a new
+              identifier.  If no symbol counter  exists  for
+              s_arg, then s_arg is returned.
+
+     NOTE: See also initsym,  newsym,  allsym,  remsym,  and
+           symstat functions.
+
+(allsym 'g_arg)
+
+     WHERE:   g_arg is a list (s_arg n_counter) or a  string
+              s_arg (equivalent to (s_arg 0)).
+
+     RETURNS: a list of all the created identifiers  between
+              n_counter  and  the current symbol counter for
+              s_arg.
+
+     EXAMPLE: (allsym 'john) ==> (john0 john1 john2)
+
+     NOTE: See also initsym,  newsym,  oldsym,  remsym,  and
+           symstat functions.
+
+(remsym 'g_arg1 ...)
+
+     WHERE:   g_argi is a  list  (s_argi  n_counteri)  or  a
+              string  s_argi (which is equivalent to (s_argi
+              0)).
+
+     RETURNS: a list of symbols s_argi with the current sym-
+              bol counters.
+
+     SIDE EFFECT: remsym remob's all the created identifiers
+                  between   zero   and  the  current  symbol
+                  counter for s_argi.
+
+
+
+
+
+
+
+
+
+
+
+
+
+     NOTE: See also initsym, newsym oldsym, allsym, and sym-
+           stat functions.
+
+(symstat 's_arg1 ...)
+
+     RETURNS: a list of pairs consisting of (s_argi symctri)
+              where   symctri  is  s_argi's  current  symbol
+              counter.
+
+     NOTE: See also initsym,  newsym,  oldsym,  allsym,  and
+           remsym functions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/usr/src/ucb/lisp/liszt/68k/Makefile b/usr/src/ucb/lisp/liszt/68k/Makefile
new file mode 100644 (file)
index 0000000..f689d1a
--- /dev/null
@@ -0,0 +1,197 @@
+#$Header: Makefile,v 1.18 83/09/12 15:27:18 layer Exp $
+#
+#                              -[Sat Jul 30 15:47:44 PDT 1983 by layer]-
+#
+#      Makefile for liszt 
+#
+# Copyright (c) 1980, 1982,  The Regents of the University of California.
+# the Copyright applies to all files referenced in this Makefile.
+# All rights reserved.  
+# Authors: John Foderaro (jkf@berkeley.ARPA)
+#         Kevin Layer (layer@berkeley.ARPA)
+#
+# this makefile creates these things:
+#   liszt - the interface to the lisp compiler.  This is used only for
+#          non virtual memory systems, because the overhead for forking
+#          the assembler is too great.
+#   nliszt - the lisp compiler. This is the default.
+#   snliszt - the lisp compiler, but interpreted.
+#   fromasm - used to build the compiler usually for the first
+#              time from only .s files.  These files are assembled
+#              and loaded into a lisp.
+#   install - install the new version created
+#   clean - remove all .o files and *nliszt's
+#   tags - a tags file for use by ex/vi
+#
+# CTE refers to compile time enviroment 
+#
+#--- Default Paths and programs
+#
+.DEFAULT:nliszt
+.SUFFIXES:
+.SUFFIXES: .l.o
+
+# DESTDIR is the relative offset of where the compiler goes
+# (when making new distributions, the `root' is often at /nbsd).
+# RootDir is the root directory of the franz lisp system
+# (this is changed when the system is configured by ../../lispconf).
+DESTDIR =
+
+LibDir = ${DESTDIR}/usr/lib/lisp
+ObjDir = ${DESTDIR}/usr/ucb
+Liszt = ${ObjDir}/liszt
+Lisp = ${ObjDir}/lisp
+#ifdef swapper
+#XLiszt = ${ObjDir}/xliszt
+#endif
+
+CFLAGS = -O # -Ddebug
+Flg =  -xqa
+
+CTESrc = ../chead.l ../cmacros.l ../const.l
+
+CTEObj= cmacros.o
+
+Src =  ../array.l ../datab.l ../decl.l ../expr.l ../fixnum.l ../funa.l\
+       ../instr.l ../vector.l ../funb.l ../func.l ../io.l\
+       ../tlev.l ../util.l ../lversion.l
+
+SharedSrc = ${CTESrc} ${Src} ../ChangeLog ../cmake.l
+
+AllSrc =  Makefile Makefile2 lisprc.l lisztrc.l liszt.c
+
+Obj = array.o vector.o datab.o decl.o expr.o fixnum.o\
+      instr.o funa.o funb.o func.o io.o tlev.o util.o lversion.o
+
+AllObj =  ${CTEObj} ${Obj}
+
+#liszt :: the user interface to xliszt
+# (only for swapped based systems, right now dual/unisoft)
+#ifdef swapper
+#liszt:        liszt.c
+#      cc $(CFLAGS) -DLISZT='"${XLiszt}"' -DAS='"${LibDir}/as"'\
+#         -o liszt liszt.c
+#else
+liszt:
+#endif
+
+donliszt:
+       rm -f nliszt
+       make Liszt=${Liszt} Lisp=${Lisp} nliszt
+
+nliszt: ${CTEObj} ${Obj} liszt ${Lisp}
+       rm -f nliszt
+       echo "(load '../cmake.l)(genl nliszt)" | ${Lisp} 
+
+#--- generate an interpreted version
+snliszt: ${Src} ${Lisp}
+       rm -f snliszt
+       echo "(load '../cmake.l)(genl snliszt slow)" | ${Lisp}
+
+# 'fromasm' is for making the compiler from
+# .s files.  On 68k systems this is much faster than
+# doing a 'make slow', then a 'make fast'.
+fromasm:       assit load liszt
+assit:
+       for i in *.s; do echo $$i; as $$i; done
+
+#--- load .o files into a lisp
+load:
+       rm -f nliszt
+       echo "(load '../cmake.l)(genl nliszt)" | ${Lisp} 
+
+# install nliszt, and if we are on a swap based system, then
+#install nliszt as xliszt, and liszt (from liszt.c) as liszt.
+install:
+#ifdef swapper
+#      mv nliszt ${XLiszt}
+#      cp liszt ${Liszt}
+#else
+       mv nliszt ${Liszt}
+#endif
+
+clean: cleanobj
+       rm -f \#* *nliszt *.s
+
+cleanobj:
+       rm -f *.[ox]
+
+#--- rules for each lisp file:
+cmacros.o: ../cmacros.l
+       ${Liszt} ${Flg} ../cmacros.l -o cmacros.o
+
+array.o: ../array.l
+       ${Liszt} ${Flg} ../array.l -o array.o
+
+instr.o: ../instr.l
+       ${Liszt} ${Flg} ../instr.l -o instr.o
+
+vector.o: ../vector.l
+       ${Liszt} ${Flg} ../vector.l -o vector.o
+
+datab.o: ../datab.l
+       ${Liszt} ${Flg} ../datab.l -o datab.o
+
+decl.o: ../decl.l
+       ${Liszt} ${Flg} ../decl.l -o decl.o
+
+expr.o: ../expr.l
+       ${Liszt} ${Flg} ../expr.l -o expr.o
+
+fixnum.o: ../fixnum.l
+       ${Liszt} ${Flg} ../fixnum.l -o fixnum.o
+
+funa.o: ../funa.l
+       ${Liszt} ${Flg} ../funa.l -o funa.o
+
+funb.o: ../funb.l
+       ${Liszt} ${Flg} ../funb.l -o funb.o
+
+func.o: ../func.l
+       ${Liszt} ${Flg} ../func.l -o func.o
+
+io.o: ../io.l
+       ${Liszt} ${Flg} ../io.l -o io.o
+
+tlev.o: ../tlev.l
+       ${Liszt} ${Flg} ../tlev.l -o tlev.o
+
+util.o: ../util.l
+       ${Liszt} ${Flg} ../util.l -o util.o
+
+lversion.o: ../lversion.l
+       ${Liszt} ${Flg} ../lversion.l -o lversion.o
+
+tags:  ../tags ${Src} ${CTESrc}
+       awk -f ../ltags ${Src} ${CTESrc} | sort > ../tags
+
+print:
+#      @pr README
+       @ls -l | pr 
+       @pr TODO Makefile* ../cmake.l lisztrc.l lisprc.l
+       @pr -h "Liszt.c (for non-VMUNIX systems only)" liszt.c
+       @/usr/local/slp -l ../lversion.l ../chead.l ../cmacros.l\
+          ../datab.l ../decl.l ../expr.l\
+          ../funa.l ../funb.l ../func.l\
+          ../fixnum.l ../array.l ../io.l ../tlev.l ../util.l
+
+iprint:
+       igrind -lsh Makefile*
+       igrind -lc -h "Liszt.c (for non-VMUNIX systems only)" liszt.c
+       vlp -p 10 ../lversion.l\
+          ../chead.l ../cmacros.l\
+          ../datab.l ../decl.l ../expr.l\
+          ../funa.l ../funb.l ../func.l\
+          ../fixnum.l ../array.l ../io.l ../tlev.l ../util.l\
+          ../cmake.l lisztrc.l lisprc.l > vlp.out
+       itroff vlp.out
+       rm vlp.out
+
+scriptcatall: ${AllSrc}
+       @../../scriptcat . liszt/68k ${AllSrc}
+
+copysource: ${AllSrc}
+       (tar cf - ${AllSrc} | (cd ${CopyTo} ; tar xf -))
+
+copyobjects: ${AllObj}
+       (tar cf - ${AllObj} | (cd ${CopyTo} ; tar xf -))
diff --git a/usr/src/ucb/lisp/liszt/68k/Makefile2 b/usr/src/ucb/lisp/liszt/68k/Makefile2
new file mode 100644 (file)
index 0000000..b93748d
--- /dev/null
@@ -0,0 +1,61 @@
+#make .s files
+
+Liszt = ./nliszt
+Flg = -Sqa
+X = ./
+
+DotSSrc = $(X)array.s $(X)cmacros.s $(X)datab.s $(X)decl.s\
+         $(X)expr.s $(X)fixnum.s $(X)funa.s $(X)funb.s $(X)func.s $(X)io.s\
+         $(X)lversion.s $(X)tlev.s $(X)util.s $(X)vector.s $(X)instr.s
+
+.DEFAULT:xtra
+
+xtra:  ${DotSSrc}
+
+scriptcatxtra:
+       @../../scriptcat . liszt/68k ${DotSSrc}
+
+$(X)array.s: ../array.l
+       ${Liszt} ${Flg} ../array.l -o $(X)array.s
+
+$(X)instr.s: ../instr.l
+       ${Liszt} ${Flg} ../instr.l -o $(X)instr.s
+
+$(X)vector.s: ../vector.l
+       ${Liszt} ${Flg} ../vector.l -o $(X)vector.s
+
+$(X)datab.s:  ../datab.l
+       ${Liszt} ${Flg} ../datab.l -o $(X)datab.s
+
+$(X)decl.s:  ../decl.l
+       ${Liszt} ${Flg} ../decl.l -o $(X)decl.s
+
+$(X)expr.s:  ../expr.l
+       ${Liszt} ${Flg} ../expr.l -o $(X)expr.s
+
+$(X)fixnum.s:  ../fixnum.l
+       ${Liszt} ${Flg} ../fixnum.l -o $(X)fixnum.s
+
+$(X)funa.s:  ../funa.l
+       ${Liszt} ${Flg} ../funa.l -o $(X)funa.s
+
+$(X)funb.s:  ../funb.l
+       ${Liszt} ${Flg} ../funb.l -o $(X)funb.s
+
+$(X)func.s:  ../func.l
+       ${Liszt} ${Flg} ../func.l -o $(X)func.s
+
+$(X)io.s:  ../io.l
+       ${Liszt} ${Flg} ../io.l -o $(X)io.s
+
+$(X)tlev.s:  ../tlev.l
+       ${Liszt} ${Flg} ../tlev.l -o $(X)tlev.s
+
+$(X)util.s:  ../util.l
+       ${Liszt} ${Flg} ../util.l -o $(X)util.s
+
+$(X)lversion.s:  ../lversion.l
+       ${Liszt} ${Flg} ../lversion.l -o $(X)lversion.s
+
+$(X)cmacros.s: ../cmacros.l
+       ${Liszt} ${Flg} ../cmacros.l -o $(X)cmacros.s
diff --git a/usr/src/ucb/lisp/liszt/ChangeLog b/usr/src/ucb/lisp/liszt/ChangeLog
new file mode 100644 (file)
index 0000000..3bd8b8e
--- /dev/null
@@ -0,0 +1,302 @@
+Sat Jul 30 15:37:40 1983 by layer
+       open code vset.  Move all vector stuff to vector.l.
+       Files: func.l, decl.l, vector.l, and cmake.l
+       (new: version 8.33)
+       
+Mon Jul 25 21:29:54 PDT 1983 by layer
+       fixed 'liszt' to mung object file header for the sun
+       File: tlev.l
+       (now: version 8.32)
+
+Mon Jul 25 07:05:49 1983 by jkf
+       fix bug whereby -mr would cause an 'comma not in backquote error'
+       because the escape character was / instead of \ when reading
+       /usr/lib/lisp/autorun.xxx
+       (now: version 8.31)
+       
+Sat Jun 25 13:28:10 1983 by jkf
+       Turn off uctolc converstion before printing bindtab.
+       This is useful for liszt in opus 38.65 and greater since it
+       will eliminate unnecessary |'s in the bindtab if uctolc
+       is need to compile the file
+       (now: version 8.29)
+       
+Thu Jun 16 21:52:59 1983 by jkf
+       fixed compilation of &aux for vax version.  Now &aux (foo foo)
+       will work if foo is special.
+       (now: version 8.28)
+       
+Wed May  4 18:32:46 1983 by layer
+       added sun autorun header to io.l
+       (now: version 8.27)
+
+Thu Mar 24 08:24:53 1983 by jkf
+       -x file will now be placed in the same place as the output
+       file (instead of the input file).
+       (now: version 8.25)
+       
+Sat Mar 19 17:49:18 1983 by jkf
+       mixed in the 68k liszt source.
+       (now: version 8.24)
+       
+Mon Mar 14 13:14:26 1983 by jkf
+       liszt used to open code 'times' if all operands were fixnums.
+       Thus (times 256 256 256 256) would open code to a 0 fixnum.
+       This is clearly wrong and liszt will now not convert times, add,
+       etc to their fixnum equivalents.  If you want fixnum semantics
+       then you must use fixnums.
+       Another bug was fixed: d-functyp would return the wrong thing
+       give a name bound to a foreign function.  now it returns 'lambda.
+       files affected: datab.l decl.l
+       (now: version 8.23)
+       
+Tue Feb 22 08:43:44 1983 by jkf
+       force jump to vecindexerr to use 'jmp', since the object
+       file might be large and the assembler is stupid
+       (now: version 8.22)
+       
+Thu Feb 10 20:39:42 1983 by jkf
+       open coded vectorp and vectorip, vsize-...
+       (now: version 8.21)
+       
+Thu Jan 20 01:57:01 1983 by layer
+       Added three features to liszt command line processing:
+       -e <expr> evaluates <expr> before compilation.
+       -i <filename> loads <filename> before compilation.
+       -S -o filename names .s file.
+       file: tlev.l
+       (now: version 8.20)
+       
+Mon Jan 17 09:41:12 1983 by jkf
+       added arg number checking and open coded &keywords.
+       (now: version 8.19)
+       
+Sun Jan 16 10:05:01 1983 by jkf
+       fixed nasty bug in d-exp which would show up if a macro
+       returned a recursive call it itself
+       (now: version 8.18)
+       
+Wed Jan 12 10:43:53 1983 by jkf
+       added open coding of vref functions
+       (now: version 8.17)
+       
+Wed Oct 27 20:24:47 1982 by jkf
+       removed references to sys_ functions, replaced them with
+       sys: functions so code will be more portable.
+       file: tlev.l
+       
+Wed Oct 27 08:15:14 1982 by jkf
+       discovered that making 'declare' a function is a bad idea because
+       if the compiler executes an interpreted function with local
+       declarations, those local declarations will seem like declarations
+       for the function begin compiled.   Thus declare is no longer a
+       special function in the compiler: it must be seen by the compiler
+       to have an effect.  Added the user callable function liszt-declare
+       which will have an effect just like declare used to: the compiler
+       will recognize it when compiling and it can be evaluated by a
+       user function.
+       (now: version 8.16)
+       
+Mon Oct 25 22:55:37 1982 by jkf
+       removed If macro definition from cmacros.l . It is now in
+       the default franz.
+       
+Mon Oct 25 09:15:18 1982 by jkf
+       catch the sigterm signal and die after removing the /tmp file.
+       (now: version 8.15)
+       
+Tue Oct 19 15:56:07 1982 by jkf
+       fixed bugin cc-arg wherein a (arg (foo)) would be compiled
+       incorrectly (it was calling zerop on a non number).
+       Added checks for cmacro and macro-autoload properties.
+       When doing macro expansion, had it stop if the same car
+       was returned.
+       (now: version 8.14)
+       
+Mon Oct 18 23:27:14 1982 by layer
+       Fixed bug in function cc-quote.  Parens in an If statement
+       were messed up.
+       
+Sat Oct  9 04:35:23 PDT 1982 by layer
+       Np-reg, Lbot-reg, oLbot-reg are now constants.  Changes
+       made to expr.l and io.l.
+
+Thu Oct  7 01:02:26 1982 by jkf
+       fixed bug in the compiler.  The compiler had neglected to enforce
+       the rule that 'macros' not be defined as local functions.
+       Now that is checked (modification to tlev.l).
+       
+Wed Oct  6 22:53:36 1982 by jkf
+       added check to make sure that a file doesn't declare a function
+       to be local that has already had a compiled call made to it.
+       This is done by placing a t under indicator g-stdref for all
+       symbols called in the 'standard' way.
+       (now: version 8.13)
+       
+Wed Oct  6 13:29:27 PDT 1982 by layer
+       put the loading of chead.l (in array.l datab.l decl.l expr.l
+       fixnum.l funa.l funb.l func.l io.l tlev.l util.l) under
+       include-if control.  Also changed chead.l.
+
+Tue Oct  5 23:36:09 PDT 1982 by layer
+       removed function d-call from expr.l, since it isn't
+       used anymore.
+
+Tue Oct  5 23:00:09 PDT 1982 by layer
+       added sccs'ed file scmake.l, so that an all interp'd
+       version of the compiler can be made without deleting
+       all the .o files.  Changes were also make to the Makefile.
+       snliszt (formerly slownliszt) now depends on source
+       files (like nliszt depends on .o files).
+
+Tue Oct  5 22:22:59 1982 by jkf
+       added argument checking.  This involved mods to expr.l to
+       do the checking and to tlev.l to save argument number
+       info while compiling.  The file /usr/lib/lisp/fcninfo.l
+       contains a description of what is known about C functions.
+       (now: version 8.12)
+       
+Mon Oct  4 14:23:29 1982 by jkf
+       turn off [load ...] message when loading in lisztrc file
+       
+Tue Sep 28 09:30:36 1982 by jkf
+       change tmp file name back to jkfnnnnn
+       (now: version 8.11)
+       
+Wed Jul 21 13:43:56 PDT 1982 by layer
+       function "liszt" in tlev.l now returns the true assembler exit
+       status (if the compile goes that far).
+
+Sat Jul  3 18:01:25 1982 by jkf
+       open code  getaux and getaccess
+       (now: version 8.10)
+       
+Wed Jun 30 18:58:32 1982 by jkf
+       look for liszt rc files without extensions.  now we look in 
+       12 places for the lisp init file:
+         { . , $HOME } { .lisztrc , lisztrc } { .o , .l , }
+       (now: version 8.09)
+       
+Thu May 27 08:19:00 1982 by jkf
+       fixed bug in d-fixnump which caused liszt to assume too often that
+       arguments are all fixnums
+       (now: version 8.08)
+       
+Wed May 12 13:46:03 1982 by jkf
+       new declaration scheme died when the object being declared
+       was a list. e.g (declare (fixnum (foo fixnum flonum)).
+       Fixed declare-handler so that cases like this are ignored.
+       (now: version 8.07)
+
+Fri May  7 19:28:04 1982 by jkf
+       allow (function (nlambda ()...)) and (function (lambda () ..))
+       (now: version 8.06)
+
+Thu May  6 15:03:50 1982 by jkf
+       support local declarations.  They are stacked on g-decls.
+       localf and macarray don't fit in too well, they should
+       be fixed.  
+       fixnum declarations now have meaning.  They will allow the
+       compiler to convert from functions like 'add1' to 1+.
+       'declare' is now a function in the compiler so declarations
+       may be fasl'ed in. [this was removed Oct 27, 1982]
+
+Thu Apr 22 20:48:25 1982 by jkf
+       #' returns a symbol now, instead of the getd of the symbol.
+       This was required for maclisp compatibility.
+       (now: version 8.05)
+
+Wed Apr 21 07:50:41 1982 by jkf
+       load in init file before compiling.  look in . first, then $HOME.
+       look for .liszt.o, .lisztrc.l, lisztrc.o, lisztrc.l
+       
+       Upon interrupt, remove temp file and exit
+       (now: version 8.04)
+
+Mon Apr 12 23:22:37 1982 by jkf
+       open code 'function'.  Now it will cause another function to be
+         generated and compiled and the function call returns the
+         bcd header for the newly created function
+       liszt-process-forms may be filled with forms to compile while 
+         compiling a form.  Unlike liszt-eof-forms, liszt-process-forms
+         are compiled at the next opportunity.
+       (now: version 8.03)
+       
+Wed Mar 31 08:47:46 1982 by jkf
+       fixed bug in which (> (or nil 9) 0) would return true. cc-eq
+       now rebinds g-trueop and g-falseop. (now: version 8.02)
+       
+Wed Mar 31 08:24:27 1982 by jkf
+       added a new file to liszt: lversion.l   It is not sccsed and it 
+       just contains the version number.  This will allow the version
+       number to be changed with ease whenever a modification is made.
+       start it at 8.01  (now: version 8.01)
+
+Fri Mar 19 11:17:12 1982 by jkf
+       did distribution. (now: version 8.00)
+
+Fri Feb 19 09:56:50 1982 by jkf
+       fixed e-docomment so that newlines in the comment will not
+       cause assembler problems [io.l]
+
+Wed Feb 17 12:46:24 1982 by jkf
+       to version 8.0 (to correspond with Opus 38)
+       
+Wed Feb 10 21:28:41 1982 by jkf
+       fixed a bug in the return function and a possible bug in go.
+       both bugs have to do with returning or going through a
+       catch or errset, which is a pretty strange thing to do anyway.
+       The fix was to keep track of the number of catches and errsets
+       before the prog to be returned from or gone into.
+       I modified d-pushframe to always push 3 args, so we can know
+       how long each frame we pop will be.
+Sat Dec  5 11:58:36 1981 by jkf
+       open coded boole (mods to decl.l and funa.l).  used the open
+       coding capability of fixnums.
+       Added three internal functions fixnum-BitXor, fixnum-BitAndNot
+       fixnum-BitOr, which are the three functions which the vax
+       can do.
+Mon Oct 26 21:15:36 1981 by jkf
+       fixed bug in d-supercxr (funa.l) which made this function
+       (cond ((setq y (cxr n zip)) (print 'hi))
+             (t (print 'lo)))
+       always prints 'hi'.  The problem was that only jump on true was
+       checked if the value of a cxr was stored somewhere.  In the case
+       above we want to jump on nil.
+       
+Sat Oct 24 16:41:03 1981 by jkf
+       -*- to version 7.1 -*-
+       Added the 'a' option to liszt, which if set will cause a 
+       special form to be output after a function is defined. that special
+       form will put a 'fcn-info' property on the function's property 
+       list.  the form of the fcn-info property is
+        (argdesc compileinfo)
+       argdesc may be nil or (x . y), the later meaning that there are a 
+       minumum of x args required and a maximum of y.  Currently lexprs
+       just put 'nil' there, but soon I will introduce a way to declare
+       min and max args for lexprs via a declare.  The compileinfo
+       is a string saying what file this came from and when it was
+       compiled.
+       
+Wed Oct 21 20:19:53 1981 by jkf
+       added functions <&, =&, and >& which are fixnum only
+       versions of <,= and >.  
+       
+Tue Oct 20 22:14:41 1981 by jkf
+       fix < and > compiling so that they are only open coded if
+       we can be sure that both operands are fixnums.  For now this
+       amounts to checking that one of the operands is a fixnum.
+       We should augment to this check also for type declarations.
+       
+Sat Oct 17 11:47:50 1981 by jkf
+       since most fixnums are in the range 0 to 1023 we can probably
+       win by doing inline checking in that range.  Thus I've added
+       the function d-fixnumbox which does an inline reboxing if
+       the number is between 0 and 1023 and otherwise calls qnewint.
+       The file changed was fixnum.l
+       
+Thu Oct  8 23:35:34 1981 by jkf
+       added cc-= to open code = if possible.  It looks for a fixnum
+       as one of the arguments and converts the = expression to 
+       (eq (cdr ..) (cdr ..)) which should do the trick.
+       
diff --git a/usr/src/ucb/lisp/liszt/Makefile b/usr/src/ucb/lisp/liszt/Makefile
new file mode 100644 (file)
index 0000000..e69a604
--- /dev/null
@@ -0,0 +1,52 @@
+#$Header: Makefile,v 1.12 83/09/12 15:26:36 layer Exp $
+#
+#makefile for misc things -- lxref and tags
+
+DESTDIR =
+ObjDir = /usr/ucb
+Liszt = ${ObjDir}/liszt
+XTR = /na/lbc/bin/extract
+
+CTESrc = chead.l cmacros.l const.l
+
+Src =  array.l datab.l decl.l expr.l fixnum.l funa.l funb.l func.l io.l \
+       vector.l instr.l tlev.l util.l lversion.l
+
+LxrefSrc = lxref.l
+
+AllSrc =  Makefile ChangeLog cmake.l ${CTESrc} ${Src} ${LxrefSrc} ltags tags
+
+.DEFAULT:lxref
+
+xtra:  ${DotSSrc}
+
+doc:
+       ${XTR} -clE "(load 'const.l)(load 'chead.l)" $(CTESrc) $(Src) > doc
+
+doc.n:
+       ${XTR} -cnlE "(load 'const.l)(load 'chead.l)" $(CTESrc) $(Src) > doc.n
+
+index:
+       ${XTR} -cli\
+       -E "(progn (chdir'vax)(load'../cmacros.l)(load'../chead.l)(chdir'..))"\
+               $(CTESrc) $(Src) > index
+
+index.n:
+       ${XTR} -cnli -T "Liszt Index" -p 8\
+       -E "(progn (chdir'vax)(load'lisprc.l)(load'../cmacros.l)(load'../chead.l)(chdir'..))"\
+       $(CTESrc) $(Src) > index.n
+
+lxref: lxref.l
+       ${Liszt} -xrq -o lxref lxref.l
+
+install: lxref
+       mv lxref ${DESTDIR}${ObjDir}/lxref
+
+scriptcatall: ${DistSrc}
+       @../scriptcat . liszt ${AllSrc}
+
+copysource: ${AllSrc}
+       (tar cf - ${AllSrc} | (cd ${CopyTo} ; tar xf -))
+
+copyobjects: ${AllObj}
+       (tar cf - ${AllObj} | (cd ${CopyTo} ; tar xf -))
diff --git a/usr/src/ucb/lisp/liszt/array.l b/usr/src/ucb/lisp/liszt/array.l
new file mode 100644 (file)
index 0000000..7c30f78
--- /dev/null
@@ -0,0 +1,74 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file array
+   "$Header: array.l,v 1.7 83/08/28 17:12:39 layer Exp $")
+
+;;; ----       a r r a y                       array referencing
+;;;
+;;;                            -[Sat Aug  6 23:59:45 1983 by layer]-
+
+
+;--- d-handlearrayref :: general array handler
+; this function is called from d-exp when the car is an array (declare macarray)
+; In the current array scheme, stores look like array references with one
+; extra argument. Thus we must determine if we are accessing or storing in
+; the array.
+; Note that we must turn g-loc to reg and g-cc to nil since, even though
+; d-supercxr handles g-loc and g-cc, d-superrplacx does not and we cannot
+; know ahead of time which one we will use.  If this seems important,
+; we can beef up d-superrplacx
+;
+(defun d-handlearrayref nil
+  (let ((spec (get (car v-form) g-arrayspecs))
+       expr
+       (g-loc 'reg)  g-cc)
+
+       (makecomment '(array ref))
+       (if (eq (1+ (length (cdr spec))) (length (cdr v-form)))
+          then (d-dostore spec (cadr v-form) (cddr v-form))
+          else (setq expr (d-arrayindexcomp (cdr v-form) (cdr spec)))
+
+               (let ((v-form `(cxr ,expr (getdata (getd ',(car v-form))))))
+                    (d-supercxr (car spec) nil)))))
+
+
+;--- d-dostore :: store value in array.
+;      spec - array descriptor from declare, e.g. (foo t 12 3 4)
+;      value - expression to calculate value to be stored.
+;      indexes - list of expressions which are the actual indicies.
+;
+(defun d-dostore (spec value indexes)
+  (let (expr gen)
+       (makecomment '(doing store))
+       ; create an expression for doing index calculation.
+       (setq expr (d-arrayindexcomp indexes (cdr spec))
+            gen  (gensym))
+
+       ; calculate value to store and stack it.
+       (d-pushargs (ncons value))
+       (rplaca g-locs gen)     ; name just stacked varib
+
+       ; do the store operation.
+       (let ((v-form `(rplacx ,expr (getdata (getd ',(car v-form)))
+                             ,gen)))
+           (d-superrplacx (car spec)))
+
+       ; move the value we stored into r0
+       (d-move 'unstack 'reg)
+       (setq g-locs (cdr g-locs))
+       (decr g-loccnt)))
+
+
+
+
+(defun d-arrayindexcomp (actual formal)
+  (if (null (cdr actual))
+      then (car actual)        ; always allow one arg
+   elseif  (eq (length actual) (length formal))
+      then (do ((ac actual (cdr ac))
+               (fo formal (cdr fo))
+               (res))
+              ((null ac) (cons '+ res))
+              (setq res (cons (if (null (cdr fo)) then (car ac)
+                                  else `(* ,(car ac) ,(apply 'times (cdr fo))))
+                              res)))
+   else (comp-err "Wrong number of subscripts to array " actual)))
diff --git a/usr/src/ucb/lisp/liszt/chead.l b/usr/src/ucb/lisp/liszt/chead.l
new file mode 100644 (file)
index 0000000..d7ad055
--- /dev/null
@@ -0,0 +1,134 @@
+;;; ----       c h e a d               header file for inclusion
+
+;$Header: chead.l,v 1.7 83/08/14 01:44:56 layer Exp $
+;
+;                      -[Sun Aug 14 01:29:25 1983 by layer]-
+
+; Copyright (c) 1982 ,  The Regents of the University of California.
+; Copyright (c) 1980 ,  The Regents of the University of California.
+; All rights reserved.  
+
+; authors: John K. Foderaro and Kevin Layer
+
+(putprop 'chead t 'version)    ; flag that this file has been loaded
+
+;--- build vax by default
+;
+(cond ((not (or (status feature for-vax) (status feature for-68k)))
+       (sstatus feature for-vax)))
+
+; global franz special variables
+(declare (special $gcprint     ; t means print stats when  gc occurs.
+                 $ldprint      ; t means print fasl messages
+                 $gccount$     ; incremented every gc
+                 $global-reg$  ; t means that np and lbot are in global regs
+                 float-format  ; printf string used to print flonums
+                 lisp-library-directory ; contains as assembler
+                 lisp-object-directory  ; contains lisp for -r option
+                 franz-minor-version-number ; just what it says
+                 ))
+
+; keep 'em sorted please!
+(declare (special
+            Liszt-file-names
+            arithequiv
+            bnp-sym
+            ch-newline
+            compiler-name
+            er-fatal
+            fl-anno
+            fl-asm
+            fl-comments
+            fl-inter
+            fl-macl
+            fl-profile
+            fl-tran
+            fl-tty
+            fl-verb
+            fl-vms
+            fl-warn
+            fl-xref
+            formsiz
+            g-allf
+            g-arginfo
+            g-args
+            g-arrayspecs
+            g-bindloc
+            g-bindtype
+            g-calltype
+            g-cc
+            g-comments
+            g-compfcn                  ; t if compiling a function
+            g-complrname
+            g-current
+            g-currentargs
+            g-decls
+            g-didvectorcode
+            g-dropnpcnt
+            g-falseop
+            g-flocal
+            g-fname
+            g-ftype
+            g-funcs
+            g-functype
+            g-ignorereg
+            g-labs
+            g-litcnt
+            g-lits
+            g-loc
+            g-localf
+            g-loccnt
+            g-locs
+            g-masklab
+            g-optionalp
+            g-reflst
+            g-refseen
+            g-regmaskvec
+            g-reguse
+            g-ret
+            g-skipcode
+            g-spec
+            g-stackspace
+            g-stdref
+            g-topsym
+            g-tran
+            g-tranloc
+            g-trancnt
+            g-trueloc
+            g-trueop
+            g-vartype
+            ibase
+            in-line-lambda-number
+            internal-macros
+            k-ftype
+            liszt-eof-forms
+            liszt-file-name
+            liszt-process-forms
+            liszt-root-name
+            macros
+            old-declare-fcn
+            old-top-level
+            original-readtable
+            piport
+            poport
+            readtable
+            special
+            twa-list
+            user-top-level
+            v-form
+            v-ifile
+            v-sfile
+            v-xfile
+            vms-pointers
+            vns-include
+            vp-sfile
+            vp-xfile
+            vps-include))
+
+(eval-when (compile eval)
+   (or (get 'const 'loaded) (load '../const.l)))
+
+; load in the macro files if compiling or interpreting.
+;
+(eval-when (compile eval)
+   (or (get 'cmacros 'version) (load 'cmacros)))
diff --git a/usr/src/ucb/lisp/liszt/cmacros.l b/usr/src/ucb/lisp/liszt/cmacros.l
new file mode 100644 (file)
index 0000000..a3e21e8
--- /dev/null
@@ -0,0 +1,208 @@
+;----------- macros for the compiler -------------
+
+(setq RCS-cmacros
+   "$Header: cmacros.l,v 1.12 83/08/24 17:15:44 layer Exp $")
+
+(declare (macros t))                   ; compile and save macros
+
+; If we are making an interpreted version, then const.l hasn't been
+; loaded yet...
+(eval-when (compile eval)
+   (or (get 'const 'loaded) (load '../const.l)))
+
+;--- comp-err
+;    comp-warn
+;    comp-note
+;    comp-gerr
+; these are the compiler message producing macros.  The form is
+; (comp-xxxx val1 val2 val3 ... valn) , all values are printed according
+;  to this scheme. If vali is an atom, it is patomed, if vali is a
+;  list, it is evaluated and printed. If vali is N a newline is printed
+; 
+; furthermore
+;    the name of the current function is printed first
+;    after comp-err prints the message, it does a throw to Comp-err .
+;    errors are preceeded by Error: 
+;      warnings by %Warning: and
+;      notes by %Note:
+;     The message is sent to the message file
+;
+(def comp-err
+   (macro (l)
+         `(progn (comp-msg "?Error: " v-ifile ": " g-fname ": "
+                           ,@(cdr l) )
+                 (setq er-fatal (1+ er-fatal))
+                 (throw nil Comp-error))))
+
+(def comp-warn
+   (macro (l)
+         `(progn (cond (fl-warn
+                           (comp-msg "%Warning: " v-ifile ": "  g-fname ": "
+                                     ,@(cdr l)))))))
+
+(def comp-note
+   (macro (l)
+         `(progn (cond (fl-verb
+                           (comp-msg "%Note: " v-ifile ": "  ,@(cdr l)))))))
+
+(def comp-gerr
+   (macro (l)
+         `(progn (comp-msg
+                     "?Error: " v-ifile ": " g-fname ": ",@(cdr l))
+                 (setq er-fatal (1+ er-fatal)))))
+
+;--- comp-msg - port
+;            - lst
+;  prints the lst to the given port.  The lst is printed in the manner
+; described above, that is atoms are patomed, and lists are evaluated
+; and printed, and N prints a newline.   The output is always drained.
+;
+(def comp-msg
+   (macro (lis)
+         (do ((xx (cdr lis) (cdr xx))
+              (res nil))
+             ((null xx)
+              `(progn ,@(nreverse (cons '(terpri) res))))
+             (setq res
+                   (cons (cond ((atom (car xx))
+                                (cond ((eq (car xx) 'N) '(terpr))
+                                      ((stringp (car xx)) `(patom ,(car xx)))
+                                      (t `(niceprint ,(car xx)))))
+                               (t `(niceprint ,(car xx))))
+                         res)))))
+
+(def niceprint
+   (macro (l)
+         `((lambda (float-format) (patom ,(cadr l))) "%.2f")))
+
+;--- standard push macro
+; (Push stackname valuetoadd)
+
+(defmacro Push (atm val)
+  `(setq ,atm (cons ,val ,atm)))
+
+;--- unpush macro - like pop except top value is thrown away
+(defmacro unpush (atm)
+  `(setq ,atm (cdr ,atm)))
+
+;--- and an increment macro
+(defmacro incr (atm)
+  `(setq ,atm (1+ ,atm)))
+
+(defmacro decr (atm)
+  `(setq ,atm (1- ,atm)))
+
+;--- add a comment
+(defmacro makecomment (arg)
+  `(cond (fl-comments (setq g-comments (cons ,arg g-comments)))))
+
+;--- add a comment irregardless of the fl-comments flag
+(defmacro forcecomment (arg)
+  `(setq g-comments (cons ,arg g-comments)))
+
+;--- write to the .s file
+(defmacro sfilewrite (arg)
+  `(patom ,arg vp-sfile))
+
+(defmacro sfilewriteln (arg)
+  `(msg (P vp-sfile) ,arg N))
+
+;--- Liszt-file  :: keep track of rcs info regarding part of Liszt
+;  This is put at the beginning of a file which makes up the lisp compiler.
+; The form used is   (Liszt-file name rcs-string)
+; where name is the name of this file (without the .l) and rcs-string.
+;
+(defmacro Liszt-file (name rcs-string)
+   `(cond ((not (boundp 'Liszt-file-names))
+          (setq Liszt-file-names (ncons ,rcs-string)))
+         (t (setq Liszt-file-names
+                  (append1 Liszt-file-names ,rcs-string)))))
+
+(eval-when (compile eval load)
+   (defun immed-const (x)
+         (get_pname (concat #+for-vax "$" #+for-68k "#" x))))
+
+; Indicate that this file has been loaded, before
+(putprop 'cmacros t 'version)
+
+;-------- Instruction Macros
+
+#+for-vax
+(defmacro e-add (src dst)
+   `(e-write3 'addl2 ,src ,dst))
+
+#+for-vax
+(defmacro e-sub (src dst)
+   `(e-write3 'subl2 ,src ,dst))
+
+#+for-vax
+(defmacro e-cmp (src dst)
+   `(e-write3 'cmpl ,src ,dst))
+
+(defmacro e-tst (src)
+   `(e-write2 'tstl ,src))
+
+(defmacro e-quick-call (what)
+   `(e-write2 #+for-vax "jsb" #+for-68k "jbsr" ,what))
+
+;--- e-add3 :: add from two sources and store in the dest
+;--- e-sub3 :: subtract from two sources and store in the dest
+
+; WARNING:  if the destination is an autoincrement addressing mode, then
+;      this will not work for the 68000, because multiple instructions
+;      are generated:
+;              (e-add3 a b "sp@+")
+;      is
+;              movl b,sp@+
+;              addl a,sp@+     (or addql)
+#+for-vax
+(defmacro e-add3 (s1 s2 dest)
+   `(e-write4 'addl3 ,s1 ,s2 ,dest))
+
+#+for-68k
+(defmacro e-add3 (s1 s2 dest)
+   `(progn
+       (e-write3 'movl ,s2 ,dest)
+       (e-add ,s1 ,dest)))
+
+#+for-vax
+(defmacro e-sub3 (s1 s2 dest)
+   `(e-write4 'subl3 ,s1 ,s2 ,dest))
+
+#+for-68k
+(defmacro e-sub3 (s1 s2 dest)
+   `(progn
+       (e-write3 'movl ,s2 ,dest)
+       (e-sub ,s1 ,dest)))
+
+(defmacro d-cmp (arg1 arg2)
+  `(e-cmp (e-cvt ,arg1) (e-cvt ,arg2)))
+
+(defmacro d-tst (arg)
+  `(e-tst (e-cvt ,arg)))
+
+;--- d-cmpnil :: compare an IADR to nil
+;
+(defmacro d-cmpnil (iadr)
+   #+for-vax `(d-tst ,iadr)
+   #+for-68k `(d-cmp 'Nil ,iadr))
+
+(defmacro e-cmpnil (eiadr)
+   #+for-vax `(break 'e-cmpnil)
+   #+for-68k `(e-cmp (e-cvt 'Nil) ,eiadr))
+
+(defmacro e-call-qnewint ()
+   `(e-quick-call '_qnewint))
+
+(defmacro C-push (src)
+   #+for-68k `(e-move ,src '#.Cstack)
+   #+for-vax `(e-write2 'pushl ,src))
+
+(defmacro L-push (src)
+   `(e-move ,src '#.np-plus))
+
+(defmacro C-pop (dst)
+   `(e-move '#.unCstack ,dst))
+
+(defmacro L-pop (dst)
+   `(e-move '#.np-minus ,dst))
diff --git a/usr/src/ucb/lisp/liszt/cmake.l b/usr/src/ucb/lisp/liszt/cmake.l
new file mode 100644 (file)
index 0000000..6313cd9
--- /dev/null
@@ -0,0 +1,36 @@
+; file which loads in all the object files and dumps them
+
+; $Header: cmake.l,v 1.6 83/08/14 01:45:39 layer Exp $
+
+;                              -[Sat Aug 13 18:03:38 1983 by layer]-
+
+;--- genl :: generate liszt
+; args are unevalated.  first arg is the name of the liszt to build
+; other args [optional]:  slow         - build interpreted.
+;
+(defun genl fexpr (args)
+   (let ((dumpname (car args))
+        (slowp (memq 'slow (cdr args))))
+      (load 'fcninfo)  ; in /usr/lib/lisp (not normally in lisp)
+      (if slowp then (load '../cmacros.l))
+      (mapc '(lambda (name)
+               (if slowp
+                  then ; lisp source is in ..
+                       (load (concat "../" name ".l"))
+                  else ; objects are in .
+                       (load name)))
+           '(decl array vector datab expr io funa funb func tlev
+                  instr fixnum util lversion))
+      (allocate 'list 400)
+      (allocate 'fixnum 10)
+      (allocate 'symbol 50)
+      (sstatus translink on)
+      (if slowp then (setq displace-macros t))
+      (sstatus nofeature for-vax) ; remove memory of what it was compiled for
+      (sstatus nofeature for-68k)
+      ;indicate type of compiler (np and lbot in global registers)
+      (setq $global-reg$ (not (status feature no-global-reg)))
+      (putprop 'chead nil 'version)  ; so the compiler can compile itself
+      (setq ER%tpl 'break-err-handler) ; in case we are using another tpl
+      ; this is a temporary measure
+      (apply 'dumplisp (list dumpname))))
diff --git a/usr/src/ucb/lisp/liszt/datab.l b/usr/src/ucb/lisp/liszt/datab.l
new file mode 100644 (file)
index 0000000..7bd168d
--- /dev/null
@@ -0,0 +1,236 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file datab
+   "$Header: datab.l,v 1.5 83/08/28 17:14:27 layer Exp $")
+
+;;; ----       d a t a b                       data base
+;;;
+;;;                            -[Sat Aug  6 23:59:11 1983 by layer]-
+
+;--- d-tranloc :: locate a function in the transfer table
+;
+; return the offset we should use for this function call
+;
+(defun d-tranloc (fname)
+   (cond ((get fname g-tranloc))
+        (t (Push g-tran fname)
+           (let ((newval (* 8 g-trancnt)))
+               (putprop fname newval g-tranloc)
+               (incr g-trancnt)
+               newval))))
+
+
+;--- d-loc :: return the location of the variable or value in IADR form 
+;      - form : form whose value we are to locate
+;
+; if we are given a xxx as form, we check yyy;
+;      xxx             yyy
+;     --------      ---------
+;      nil          Nil is always returned
+;      symbol       return the location of the symbols value, first looking
+;                   in the registers, then on the stack, then the bind list.
+;                   If g-ingorereg is t then we don't check the registers.
+;                   We would want to do this if we were interested in storing
+;                   something in the symbol's value location.
+;      number       always return the location of the number on the bind
+;                   list (as a (lbind n))
+;      other        always return the location of the other on the bind
+;                   list (as a (lbind n))
+;
+(defun d-loc (form)
+   (if (null form) then 'Nil
+    elseif (numberp form) then
+        (if (and (fixp form) (greaterp form -1025) (lessp form 1024))
+            then `(fixnum ,form)               ; small fixnum
+            else (d-loclit form nil))
+    elseif (symbolp form) 
+       then (if (and (null g-ignorereg) (car (d-bestreg form nil))) thenret
+               else (if (d-specialp form) then (d-loclit form t)
+                        else (do ((ll g-locs (cdr ll)) ; check stack
+                                  (n g-loccnt))
+                                 ((null ll)
+                                  (comp-warn (or form)
+                                             " declared special by compiler")
+                                  (d-makespec form)
+                                  (d-loclit form t))
+                                 (if (atom (car ll))
+                                     then (if (eq form (car ll))
+                                              then (return `(stack ,n))
+                                              else (setq n (1- n)))))))
+       else (d-loclit form nil)))
+
+
+;--- d-loclit :: locate or add litteral to bind list
+;      - form : form to check for and add if not present
+;      - flag : if t then if we are given a symbol, return the location of
+;               its value, else return the location of the symbol itself
+;
+; scheme: we share the locations of atom (symbols,numbers,string) but always
+;       create a fresh copy of anything else.
+(defun d-loclit (form flag)
+   (prog (loc onplist symboltype)
+       (if (null form) 
+          then (return 'Nil)
+       elseif (symbolp form)
+          then (setq symboltype t)
+               (cond ((setq loc (get form g-bindloc))
+                      (setq onplist t)))
+       elseif (atom form)
+          then (do ((ll g-lits (cdr ll))       ; search for atom on list
+                    (n g-litcnt (1- n)))
+                   ((null ll))
+                   (if (eq form (car ll))
+                       then (setq loc n)       ; found it
+                            (return))))        ; leave do
+       (if (null loc)
+          then (Push g-lits form)
+               (setq g-litcnt (1+ g-litcnt)
+                     loc g-litcnt)
+               (cond ((and symboltype (null onplist))
+                      (putprop form loc g-bindloc))))
+
+       (return (if (and flag symboltype) then `(bind ,loc)
+                  else `(lbind ,loc)))))
+                            
+
+
+;--- d-locv :: find the location of a value cell, and dont return a register
+;
+(defun d-locv (sm)
+  (let ((g-ignorereg t))
+       (d-loc sm)))
+
+
+;--- d-simple :: see of arg can be addresses in one instruction
+; we define simple and really simple as follows
+;  <rsimple> ::= number
+;               quoted anything
+;               local symbol
+;               t
+;               nil
+;  <simple>  ::= <rsimple>
+;               (cdr <rsimple>)
+;               global symbol
+;
+(defun d-simple (arg)
+   (let (tmp)
+       (if (d-rsimple arg) thenret
+       elseif (atom arg) then (d-loc arg)
+       elseif (and (memq (car arg) '(cdr car cddr cdar))
+                   (setq tmp (d-rsimple (cadr arg))))
+          then (if (eq 'Nil tmp) then tmp
+                elseif (atom tmp)
+                   then #+for-vax
+                        (if (eq 'car (car arg))
+                            then `(racc 4 ,tmp)
+                         elseif (eq 'cdr (car arg))
+                            then `(racc 0 ,tmp)
+                         elseif (eq 'cddr (car arg))
+                            then `(racc * 0 ,tmp)
+                         elseif (eq 'cdar (car arg))
+                            then `(racc * 4 ,tmp))
+                        #+for-68k
+                        (if (eq 'car (car arg))
+                            then `(racc 4 ,tmp)
+                         elseif (eq 'cdr (car arg))
+                            then `(racc 0 ,tmp))
+                elseif (not (eq 'cdr (car arg)))
+                   then nil
+                elseif (eq 'lbind (car tmp))
+                   then `(bind ,(cadr tmp))
+                elseif (eq 'stack (car tmp))
+                   then `(vstack ,(cadr tmp))
+                elseif (eq 'fixnum (car tmp))
+                   then `(immed ,(cadr tmp))
+                elseif (atom (car tmp))
+                   then `(0 ,(cadr tmp))
+                   else (comp-err "bad arg to d-simple: " (or arg))))))
+
+(defun d-rsimple (arg)
+   (if (atom arg) then
+       (if (null arg) then 'Nil
+       elseif (eq t arg) then 'T
+       elseif (or (numberp arg)
+                  (memq arg g-locs)) 
+          then (d-loc arg)
+          else (car (d-bestreg arg nil)))
+    elseif (eq 'quote (car arg)) then (d-loclit (cadr arg) nil)))
+
+;--- d-specialp :: check if a variable is special
+; a varible is special if it has been declared as such, or if
+; the variable special is t
+(defun d-specialp (vrb)
+  (or special
+      (eq 'special (d-findfirstprop vrb 'bindtype))   ; local special decl
+      (eq 'special (get vrb g-bindtype))))
+
+(defun d-fixnump (vrb)
+   (and (symbolp vrb)
+       (or (eq 'fixnum (d-findfirstprop vrb 'vartype))
+           (eq 'fixnum (get vrb g-vartype)))))
+
+;--- d-functyp :: return the type of function
+;      - name : function name
+;
+; If name had a macro function definition, we return `macro'.  Otherwise
+; we see if name as a declared type, if so we return that.  Otherwise
+; we see if name is defined and we return that if so, and finally if
+; we have no idea what this function is, we return lambda.
+;   This is not really satisfactory, but will handle most cases.
+;
+; If macrochk is nil then we don't check for the macro case.  This
+; is important to prevent recursive macroexpansion.
+;
+(defun d-functyp (name macrochk)
+   (let (func ftyp)
+      (if (atom name) 
+        then
+             (setq func (getd name))
+             (setq ftyp (if (and macrochk (get name 'cmacro)) ;compiler macro
+                           then 'cmacro
+                         elseif (bcdp func)
+                           then (let ((type (getdisc func)))
+                                   (if (memq type '(lambda nlambda macro))
+                                      then type
+                                    elseif (stringp type)
+                                      then 'lambda     ; foreign function
+                                      else (comp-warn
+                                              "function "
+                                              name
+                                              " has a strange discipline "
+                                              type)
+                                           'lambda     ; assume lambda
+                                   ))
+                         elseif (dtpr func)
+                           then (car func)
+                         elseif (and macrochk (get name 'macro-autoload))
+                           then 'macro))
+             (if (memq ftyp '(macro cmacro)) then ftyp
+              elseif (d-findfirstprop name 'functype) thenret
+              elseif (get name g-functype) thenret  ; check if declared first
+              elseif ftyp thenret
+                else 'lambda)
+        else 'lambda)))                ; default is lambda
+
+;--- d-allfixnumargs :: check if all forms are fixnums
+; make sure all forms are fixnums or symbols whose declared type are fixnums
+;
+(defun d-allfixnumargs (forms)
+   (do ((xx forms (cdr xx))
+       (arg))
+       ((null xx) t)
+       (cond ((and (fixp (setq arg (car xx))) (not (bigp arg))))
+            ((d-fixnump arg))
+            (t (return nil)))))
+
+             
+(defun d-findfirstprop (name type)
+   (do ((xx g-decls (cdr xx))
+       (rcd))
+       ((null xx))
+       (if (and (eq name (caar xx))
+               (get (setq rcd (cdar xx)) type))
+         then (return rcd))))
+
+             
+
+
diff --git a/usr/src/ucb/lisp/liszt/decl.l b/usr/src/ucb/lisp/liszt/decl.l
new file mode 100644 (file)
index 0000000..45e911f
--- /dev/null
@@ -0,0 +1,365 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file decl
+   "$Header: decl.l,v 1.8 83/08/28 17:13:00 layer Exp $")
+
+;;; ----       d e c l         declaration handling
+;;;
+;;;                            -[Sat Aug  6 23:58:35 1983 by layer]-
+
+
+(setq original-readtable readtable)
+(setq raw-readtable (makereadtable t))
+
+;--- compile-fcn  :: declare a open coded function
+; name - name of the function
+; fcnname - function to be funcall'ed to handle the open coding
+; indicator -  describes what the fcnname will do, one of
+;              fl-expr : will compile the expression and leave the
+;                      result in r0.  Will ignore g-cc and g-loc
+;              fl-exprcc: will compile the expression and leave the
+;                      result in g-loc.  Will handle g-cc
+;              fl-exprm: will just return another form to be d-exp'ed
+; args - (optional) description of the arguments to this function.
+;      form: (min-args . max-args) .  If max-args is nil, then there is
+;              no max.  This is usually done in /usr/lib/lisp/fcninfo.l.
+;
+(defmacro compile-fcn (name fcnname indicator &optional (args nil args-p))
+   `(progn (putprop ',name ',fcnname ',indicator)
+          ;; don't do this here, done in fcn-info
+          ,@(cond (args-p `((putprop ',name (list ',args) 'fcn-info))))))
+
+          
+;--- special handlers
+(compile-fcn and       cc-and          fl-exprcc)
+(compile-fcn arg       cc-arg          fl-exprcc)
+(compile-fcn assq      cm-assq         fl-exprm)
+(compile-fcn atom      cc-atom         fl-exprcc)
+(compile-fcn bigp      cc-bigp         fl-exprcc)
+(compile-fcn bcdcall   c-bcdcall       fl-expr)
+(compile-fcn Internal-bcdcall c-Internal-bcdcall fl-expr)
+(compile-fcn bcdp      cc-bcdp         fl-exprcc)
+#+for-vax
+(compile-fcn boole     c-boole         fl-expr)
+(compile-fcn *catch    c-*catch        fl-expr)
+(compile-fcn comment   cc-ignore       fl-exprcc)
+(compile-fcn cond      c-cond          fl-expr)
+(compile-fcn cons      c-cons          fl-expr)
+(compile-fcn cxr       cc-cxr          fl-exprcc)
+(compile-fcn declare   c-declare       fl-expr)
+(compile-fcn do                c-do            fl-expr)
+(compile-fcn liszt-internal-do         c-do    fl-expr)
+(compile-fcn dtpr      cc-dtpr         fl-exprcc)
+(compile-fcn eq                cc-eq           fl-exprcc)
+(compile-fcn equal     cc-equal        fl-exprcc)
+(compile-fcn errset    c-errset        fl-expr)
+(compile-fcn fixp      cc-fixp         fl-exprcc)
+(compile-fcn floatp    cc-floatp       fl-exprcc)
+(compile-fcn funcall   c-funcall       fl-expr)
+(compile-fcn function  cc-function     fl-exprcc)
+(compile-fcn get       c-get           fl-expr)
+(compile-fcn getaccess  cm-getaccess    fl-exprm)
+(compile-fcn getaux    cm-getaux       fl-exprm)
+(compile-fcn getd      cm-getd         fl-exprm)
+(compile-fcn getdata   cm-getdata      fl-exprm)
+(compile-fcn getdisc   cm-getdisc      fl-exprm)
+(compile-fcn go                c-go            fl-expr)
+(compile-fcn list      c-list          fl-expr)
+(compile-fcn map       cm-map          fl-exprm)
+(compile-fcn mapc      cm-mapc         fl-exprm)
+(compile-fcn mapcan    cm-mapcan       fl-exprm)
+(compile-fcn mapcar    cm-mapcar       fl-exprm)
+(compile-fcn mapcon    cm-mapcon       fl-exprm)
+(compile-fcn maplist   cm-maplist      fl-exprm)
+(compile-fcn memq      cc-memq         fl-exprcc)
+(compile-fcn ncons     cm-ncons        fl-exprm)
+(compile-fcn not       cc-not          fl-exprcc)
+(compile-fcn null      cc-not          fl-exprcc)
+(compile-fcn numberp   cc-numberp      fl-exprcc)
+(compile-fcn or                cc-or           fl-exprcc)
+(compile-fcn prog      c-prog          fl-expr)
+(compile-fcn progn     cm-progn        fl-exprm)
+(compile-fcn prog1     cm-prog1        fl-exprm)
+(compile-fcn prog2     cm-prog2        fl-exprm)
+(compile-fcn progv     c-progv         fl-expr)
+(compile-fcn quote     cc-quote        fl-exprcc)
+(compile-fcn return    c-return        fl-expr)
+(compile-fcn rplaca    c-rplaca        fl-expr)
+(compile-fcn rplacd    c-rplacd        fl-expr)
+(compile-fcn rplacx    c-rplacx        fl-expr)
+(compile-fcn *rplacx   c-rplacx        fl-expr)
+(compile-fcn setarg    c-setarg        fl-expr)
+(compile-fcn setq      cc-setq         fl-exprcc)
+(compile-fcn stringp   cc-stringp      fl-exprcc)
+(compile-fcn symbolp   cc-symbolp      fl-exprcc)
+(compile-fcn symeval   cm-symeval      fl-exprm)
+(compile-fcn *throw    c-*throw        fl-expr)
+(compile-fcn typep     cc-typep        fl-exprcc)
+(compile-fcn vectorp           cc-vectorp      fl-exprcc)
+(compile-fcn vectorip          cc-vectorip     fl-exprcc)
+(compile-fcn vset      cc-vset         fl-exprcc)
+(compile-fcn vseti-byte cc-vseti-byte  fl-exprcc)
+(compile-fcn vseti-word cc-vseti-word  fl-exprcc)
+(compile-fcn vseti-long cc-vseti-long  fl-exprcc)
+(compile-fcn vref      cc-vref         fl-exprcc)
+(compile-fcn vrefi-byte cc-vrefi-byte  fl-exprcc)
+(compile-fcn vrefi-word cc-vrefi-word  fl-exprcc)
+(compile-fcn vrefi-long cc-vrefi-long  fl-exprcc)
+(compile-fcn vsize     c-vsize         fl-expr)
+(compile-fcn vsize-byte        c-vsize-byte    fl-expr)
+(compile-fcn vsize-word        c-vsize-word    fl-expr)
+
+(compile-fcn zerop     cm-zerop        fl-exprm)
+; functions which expect fixnum operands 
+
+
+(compile-fcn + c-fixnumop  fl-expr)
+#+for-vax (putprop '+ 'addl3 'fixop)
+#+for-68k (putprop '+ 'addl 'fixop)
+
+(compile-fcn - c-fixnumop fl-expr)
+#+for-vax (putprop '- 'subl3 'fixop)
+#+for-68k (putprop '- 'subl 'fixop)
+
+#+for-vax
+(progn 'compile
+   (compile-fcn * c-fixnumop fl-expr)
+   (putprop '* 'mull3 'fixop)
+
+   (compile-fcn / c-fixnumop fl-expr)
+   (putprop '/ 'divl3 'fixop))
+
+;-- boole's derivatives
+#+for-vax
+(progn 'compile
+   (compile-fcn fixnum-BitOr c-fixnumop fl-expr)
+   (putprop 'fixnum-BitOr 'bisl3 'fixop)
+
+   (compile-fcn fixnum-BitAndNot c-fixnumop fl-expr)
+   (putprop 'fixnum-BitAndNot 'bicl3 'fixop)
+
+   (compile-fcn fixnum-BitXor c-fixnumop fl-expr)
+   (putprop 'fixnum-BitXor 'xorl3 'fixop))
+
+(compile-fcn 1+        cc-oneplus  fl-exprcc)
+(compile-fcn 1-                cc-oneminus fl-exprcc)
+
+#+for-vax
+(compile-fcn \\        c-\\    fl-expr)   ; done in the old way, should be modified
+
+; these have typically fixnum operands, but not always 
+
+
+; these without the & can be both fixnum or both flonum
+;
+(compile-fcn   <       cm-<    fl-exprm)
+(compile-fcn   <&      cc-<&   fl-exprcc)
+
+(compile-fcn   >       cm->    fl-exprm)
+(compile-fcn   >&      cc->&   fl-exprcc)
+
+(compile-fcn   =       cm-=            fl-exprm)
+(compile-fcn   =&      cm-=&           fl-exprm)
+
+; functions which can only be compiled
+(compile-fcn assembler-code c-assembler-code fl-expr)
+(compile-fcn fixnum-cxr cm-fixnum-cxr fl-exprm)
+(compile-fcn internal-fixnum-box c-internal-fixnum-box fl-expr)
+(compile-fcn offset-cxr cc-offset-cxr fl-exprcc)
+(compile-fcn internal-bind-vars c-internal-bind-vars fl-expr)
+(compile-fcn internal-unbind-vars c-internal-unbind-vars fl-expr)
+
+; functions which can be converted to fixnum functions if
+; proper declarations are done
+(mapc
+   '(lambda (arg) (putprop (car arg) (cdr arg) 'if-fixnum-args))
+   '((lessp . <&) (greaterp . >&) (= . =&) (equal . =&)))
+     
+
+;--- doevalwhen, process evalwhen directive. This is inadequate.
+;
+(def doevalwhen 
+      (lambda (v-f)
+             (prog (docom dolod)
+                   (setq docom (memq 'compile (cadr v-f))
+                         
+                         dolod (memq 'load (cadr v-f)))
+                   (mapc '(lambda (frm) (cond (docom (eval frm)))
+                                        (cond (dolod 
+                                               ((lambda (internal-macros) 
+                                                        (liszt-form frm))
+                                                t))))
+                         (cddr v-f)))))
+
+\f
+;---- declare - the compiler version of the declare function
+;      process the declare forms given. We evaluate each arg
+;
+(defun liszt-declare fexpr (forms)
+   (cond ((status feature complr)
+         (do ((i forms (cdr i)))
+             ((null i))
+             (cond ((and (atom (caar i))
+                         (getd (caar i)))
+                    (eval (car i))) ; if this is a function
+                   (t (comp-warn "Unknown declare attribute: " (car i))))))))
+
+;---> handlers for declare forms
+; declaration information for declarations which occur outside of
+; functions is stored on the property list for rapid access.
+; The indicator to look under is the value of one of the symbols:
+;      g-functype, g-vartype, g-bindtype, or g-calltype
+;  The value of the property is the declared function, declaration, binding
+;      or call type for that variable.
+; For local declarations, the information is kept on the g-decls stack.
+; It is an assq list, the car of which is the name of the variable or
+; function name, the cdr of which is the particular type.  To tell
+; whether the particular type is a function type declaration, check the
+; property list of the particular type for a 'functype' indicator.
+; Likewise, to see if a particular type is a variable declaration, look
+; for a 'vartype' indicator on the particular type's property list.
+;
+(defmacro declare-handler (args name type toplevind)
+   `(mapc '(lambda (var)
+             (cond ((symbolp var)
+                    (cond (g-compfcn   ; if compiling a function
+                             (Push g-decls (cons var ',name)))
+                          (t          ; if at top level
+                             (putprop var ',name ,toplevind))))))
+         ,args))
+
+   
+(defun *fexpr fexpr (args)
+   (declare-handler args nlambda functype g-functype))
+
+(defun nlambda fexpr (args)
+   (declare-handler args nlambda functype g-functype))
+
+(defun *expr fexpr (args)
+   (declare-handler args lambda functype g-functype))
+
+(defun lambda fexpr (args)
+   (declare-handler args lambda functype g-functype))
+
+(defun *lexpr fexpr (args)
+   (declare-handler args lexpr functype g-functype))
+
+(defun special fexpr (args)
+   (declare-handler args special bindtype g-bindtype))
+
+(defun unspecial fexpr (args)
+   (declare-handler args unspecial bindtype g-bindtype))
+
+(defun fixnum fexpr (args)
+   (declare-handler args fixnum vartype g-vartype))
+
+(defun flonum fexpr (args)
+   (declare-handler args flonum vartype g-vartype))
+
+(defun notype fexpr (args)
+   (declare-handler args notype vartype g-vartype))
+
+
+
+;--- special case, this is only allowed at top level.  It will
+; be removed when vectors are fully supported
+(def macarray 
+  (nlambda (v-l)
+          (mapc '(lambda (x)
+                         (if (dtpr x)
+                             then (putprop (car x) (cdr x) g-arrayspecs)
+                                  (putprop (car x) 'array  g-functype)
+                             else (comp-err "Bad macerror form" x)))
+                v-l)))
+
+
+(def macros 
+  (nlambda (args) (setq macros (car args))))
+
+(def specials
+  (nlambda (args) (setq special (car args))))
+
+;--- *args
+; form is (declare (*args minargs maxargs))
+; this must occur within a function definition or it is an error
+;
+(def *args
+   (nlambda (args)
+           (if (not g-compfcn)
+              then (comp-err
+                      " *args declaration not given within a function definition "
+                      args))
+           (let (min max)
+              (if (not (= (length args) 2))
+                 then (comp-err " *args declaration must have two args: "
+                                args))
+              (setq min (car args) max (cadr args))
+              (if (not (and (or (null min) (fixp min))
+                            (or (null max) (fixp max))))
+                 then (comp-err " *args declaration has illegal values: "
+                                args))
+              (setq g-arginfo (cons min max))
+              (putprop g-fname (list g-arginfo) 'fcn-info))))
+
+;--- *arginfo
+; designed to be used at top level, but can be used within  function
+; form: (declare (*arginfo (append 2 nil) (showstack 0 1)))
+;
+(def *arginfo
+   (nlambda (args)
+      (do ((xx args (cdr xx))
+          (name)
+          (min)
+          (max))
+         ((null xx))
+         (if (and (dtpr (car xx))
+                  (eq (length (car xx)) 3))
+            then (setq name (caar xx)
+                       min  (cadar xx)
+                       max  (caddar xx))
+                 (if (not (and (symbolp name)
+                               (or (null min) (fixp min))
+                               (or (null max) (fixp max))))
+                    then (comp-err " *arginfo, illegal declaration "
+                                   (car xx))
+                    else (putprop name (list (cons min max)) 'fcn-info))))))
+                                                   
+   
+;--- another top level only.
+;
+(def localf
+  (nlambda (args)
+     (mapc '(lambda (ar)
+              (if (null (get ar g-localf))
+                 then (putprop ar
+                               (cons (d-genlab) -1)
+                               g-localf))
+              (if (get ar g-stdref)
+                 then (comp-err
+                        "function " ar " is being declared local" N
+                      " yet it has already been called in a non local way")))
+          args)))
+
+; g-decls is a stack of forms like
+;  ((foo . special) (bar . fixnum) (pp . nlambda))
+; there are 4 types of cdr's:
+;      function types (lambda, nlambda, lexpr)
+;      variable types (fixnum, flonum, notype)
+;      call types     (localf, <unspecified>)
+;      bind types     (special, unspecial)
+;
+(mapc '(lambda (x) (putprop x t 'functype)) '(lambda nlambda lexpr))
+(mapc '(lambda (x) (putprop x t 'vartype))  '(fixnum flonum notype))
+(mapc '(lambda (x) (putprop x t 'calltype)) '(localf))
+(mapc '(lambda (x) (putprop x t 'bindtype)) '(special unspecial))
+
+;---> end declare form handlers
+
+
+
+
+
+
+;--- d-makespec :: declare a variable to be special
+;
+(defun d-makespec (vrb)
+  (putprop vrb 'special g-bindtype))
diff --git a/usr/src/ucb/lisp/liszt/expr.l b/usr/src/ucb/lisp/liszt/expr.l
new file mode 100644 (file)
index 0000000..76bbc7d
--- /dev/null
@@ -0,0 +1,434 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file expr
+   "$Header: expr.l,v 1.12 83/09/06 21:46:46 layer Exp $")
+
+;;; ----       e x p r                         expression compilation
+;;;
+;;;                            -[Fri Sep  2 22:10:20 1983 by layer]-
+
+
+;--- d-exp :: compile a lisp expression
+;      v-form : a lisp expression to compile
+; returns an IADR which tells where the value was located.
+;
+
+(defun d-exp (v-form)
+  (prog (first resloc tmp ftyp nomacrop)
+    begin
+       (if (atom v-form)
+           then (setq tmp (d-loc v-form))              ;locate vrble
+                (if (null g-loc)
+                    then (if g-cc then (d-cmpnil tmp))
+                   else (d-move tmp g-loc)
+                        #+for-68k (if g-cc then (d-cmpnil tmp)))
+                (d-handlecc)
+                (return tmp)
+
+        elseif (atom (setq first (car v-form)))
+          then ; the form (*no-macroexpand* <expr>)
+               ; turns into <expr>, and prevents <expr> from
+               ; being macroexpanded (at the top level)
+               (if (eq '*no-macroexpand* first)
+                  then (setq v-form (cadr v-form)
+                             nomacrop t)
+                       (go begin))
+               (if (and fl-xref (not (get first g-refseen)))
+                    then (Push g-reflst first)
+                         (putprop first t g-refseen))
+                (setq ftyp (d-functyp first (if nomacrop then nil
+                                               else 'macros-ok)))
+                ; if nomacrop is t, then under no circumstances
+                ; permit the form to be macroexpanded
+                (if (and nomacrop (eq ftyp 'macro))
+                    then (setq ftyp 'lambda))
+                ; If the resulting form is type macro or cmacro,
+                ; then call the appropriate function to macro-expand
+                ; it.
+                (if (memq ftyp '(macro cmacro))
+                   then (setq tmp v-form)      ; remember original form
+                        (if (eq 'macro ftyp)
+                            then (setq v-form (apply first v-form))
+                          elseif (eq 'cmacro ftyp)
+                            then (setq v-form (apply (get first 'cmacro)
+                                                     v-form)))
+                         ; If the resulting form is the same as
+                         ; the original form, then we don't want to
+                         ; macro expand again.  We call d-functyp and tell
+                         ; it that we want a second opinion
+                         (if (and (eq (car v-form) first)
+                                  (equal tmp v-form))
+                            then (setq ftyp (d-functyp first nil))
+                            else (go begin))) ; retry with what we have
+
+                (if (and (setq tmp (get first 'if-fixnum-args))
+                             (d-allfixnumargs (cdr v-form)))
+                   then (setq v-form (cons tmp (cdr v-form)))
+                        (go begin)
+                 elseif (setq tmp (get first 'fl-exprcc))
+                   then (d-argnumchk 'hard)
+                        (return (funcall tmp))
+                 elseif (setq tmp (get first 'fl-exprm))
+                   then (d-argnumchk 'hard)
+                        (setq v-form (funcall tmp))
+                        (go begin)
+                 elseif (setq tmp (get first 'fl-expr))
+                   then (d-argnumchk 'hard)
+                        (funcall tmp)
+                 elseif (setq tmp (or (and (eq 'car first)
+                                           '( a ))
+                                      (and (eq 'cdr first)
+                                           '( d ))
+                                      (d-cxxr first)))
+                   then (d-argcheckit '(1 . 1) (length (cdr v-form)) 'hard)
+                        (return (cc-cxxr (cadr v-form) tmp))
+                  elseif (eq 'nlambda ftyp)
+                   then (d-argnumchk 'soft)
+                        (d-callbig first `(',(cdr v-form)) nil)
+                  elseif (or (eq 'lambda ftyp) (eq 'lexpr ftyp))
+                    then (setq tmp (length v-form))
+                         (d-argnumchk 'soft)
+                         (d-callbig first (cdr v-form) nil)
+                  elseif (eq 'array ftyp)
+                   then (d-handlearrayref)
+                 elseif (eq 'macro ftyp)
+                   then (comp-err "infinite macro expansion " v-form)
+                   else (comp-err "internal liszt err in d-exp" v-form))
+
+        elseif (eq 'lambda (car first))
+           then (c-lambexp)
+
+        elseif (or (eq 'quote (car first)) (eq 'function (car first)))
+           then (comp-warn "bizzare function name " (or first))
+                (setq v-form (cons (cadr first) (cdr v-form)))
+                (go begin)
+               
+        else (comp-err "bad expression" (or v-form)))
+
+       (if (null g-loc)
+           then (if g-cc then (d-cmpnil 'reg))
+        elseif (memq g-loc '(reg #+for-vax r0 #+for-68k d0))
+           then (if g-cc then (d-cmpnil 'reg))
+          else (d-move 'reg g-loc)
+               #+for-68k (if g-cc then (d-cmpnil 'reg)))
+       (if g-cc then (d-handlecc))))
+
+;--- d-exps :: compile a list of expressions
+;      - exps : list of expressions
+; the last expression is evaluated according to g-loc and g-cc, the others
+; are evaluated with g-loc and g-cc nil.
+;
+(defun d-exps (exps)
+  (d-exp (do ((ll exps (cdr ll))
+             (g-loc nil)
+             (g-cc  nil)
+             (g-ret nil))
+            ((null (cdr ll)) (car ll))
+            (d-exp (car ll)))))
+
+
+;--- d-argnumchk :: check that the correct number of arguments are given
+; v-form (global) contains the expression to check
+; class: hard or soft, hard means that failure is an error, soft means
+;      warning
+(defun d-argnumchk (class)
+   (let ((info (car (get (car v-form) 'fcn-info)))
+        (argsize (length (cdr v-form))))
+      (if info then (d-argcheckit info argsize class))))
+
+;--- d-argcheckit
+; info - arg information form:  (min# . max#)  max# of nil means no max
+; numargs - number of arguments given
+; class - hard or soft
+; v-form(global) - expression begin checked
+;
+(defun d-argcheckit (info numargs class)
+   (if (and (car info) (< numargs (car info)))
+      then (if (eq class 'hard)
+             then (comp-err
+                     (difference (car info) numargs)
+                     " too few argument(s) given in this expression:" N
+                     v-form)
+             else (comp-warn
+                     (difference (car info) numargs)
+                     " too few argument(s) given in this expression:" N
+                     v-form))
+    elseif (and (cdr info) (> numargs (cdr info)))
+      then (if (eq class 'hard)
+             then (comp-err
+                     (difference numargs (cdr info))
+                     " too many argument(s) given in this expression:" N
+                     v-form)
+             else (comp-warn
+                     (difference numargs (cdr info))
+                     " too many argument(s) given in this expression:" N
+                     v-form))))
+
+;--- d-pushargs :: compile and push a list of expressions
+;      - exps : list of expressions
+; compiles and stacks a list of expressions
+;
+(defun d-pushargs (args)
+   (if args then
+       (do ((ll args (cdr ll))
+           (g-loc 'stack)
+           (g-cc nil)
+           (g-ret nil))
+          ((null ll))
+          (d-exp (car ll))
+          (push nil g-locs)
+          (incr g-loccnt))))
+
+;--- d-cxxr :: split apart a cxxr function name
+;      - name : a possible cxxr function name
+; returns the a's and d's between c and r in reverse order, or else
+;  returns nil if this is not a cxxr name
+;
+(defun d-cxxr (name)
+  (let ((expl (explodec name)))
+       (if (eq 'c (car expl))                  ; must begin with c
+          then (do ((ll (cdr expl) (cdr ll))
+                    (tmp)
+                    (res))
+                   (nil)
+                   (setq tmp (car ll))
+                   (if (null (cdr ll)) 
+                       then (if (eq 'r tmp)    ; must end in r
+                                then (return res)
+                                else (return nil))
+                    elseif (or (eq 'a tmp)     ; and contain only a's and d's
+                               (eq 'd tmp))
+                       then (setq res (cons tmp res))
+                    else (return nil))))))
+
+
+;--- d-callbig :: call a local, global or bcd  function        
+;
+; name is the name of the function we are to call
+; args are the arguments to evaluate and call the function with
+; if bcdp is t then we are calling through a binary object and thus
+; name is ingored.
+;
+#+for-vax
+(defun d-callbig (name args bcdp)
+  (let ((tmp (get name g-localf))
+       c)
+       (forcecomment `(calling ,name))
+       (if (d-dotailrecursion name args) thenret
+        elseif tmp then ;-- local function call
+                   (d-pushargs args)
+                   (e-quick-call (car tmp))
+                   (setq g-locs (nthcdr (setq c (length args)) g-locs))
+                   (setq g-loccnt (- g-loccnt c))
+       else (if bcdp           ;-- bcdcall
+                then (d-pushargs args)
+                     (setq c (length args))
+                     (d-bcdcall c)
+              elseif fl-tran   ;-- transfer table linkage
+                then (d-pushargs args)
+                   (setq c (length args))
+                   (d-calltran name c)
+                   (putprop name t g-stdref)   ; remember we've called this
+              else ;--- shouldn't get here
+                   (comp-err " bad args to d-callbig : "
+                             (or name args)))
+            (setq g-locs (nthcdr c g-locs))
+            (setq g-loccnt (- g-loccnt c)))
+       (d-clearreg)))
+
+#+for-68k
+(defun d-callbig (name args bcdp)
+  (let ((tmp (get name g-localf))
+       c)
+       (forcecomment `(calling ,name))
+       (if (d-dotailrecursion name args)
+          thenret
+        elseif tmp then ;-- local function call
+                   (d-pushargs args)
+                   (setq c (length args))
+                   (if (null $global-reg$) then
+                       (e-write3 'lea `(,(* -4 c) #.np-reg) 'a5)
+                       (e-move 'a5 '#.lbot-sym)
+                       (e-move '#.np-reg '#.np-sym))
+                   (e-quick-call (car tmp))
+                   (setq g-locs (nthcdr c g-locs))
+                   (setq g-loccnt (- g-loccnt c))
+       else (if bcdp           ;-- bcdcall
+                then (d-pushargs args)
+                     (setq c (length args))
+                     (d-bcdcall c)
+              elseif fl-tran   ;-- transfer table linkage
+                then (d-pushargs args)
+                   (setq c (length args))
+                   (d-calltran name c)
+                   (putprop name t g-stdref)   ; remember we've called this
+              else ;--- shouldn't get here
+                   (comp-err " bad args to d-callbig : "
+                             (or name args)))
+            (setq g-locs (nthcdr c g-locs))
+            (setq g-loccnt (- g-loccnt c)))
+       (d-clearreg)))
+
+;--- d-calltran :: call a function through the transfer table
+;  name - name of function to call
+;  c - number of arguments to the function
+;
+#+for-vax
+(defun d-calltran (name c)
+   (if $global-reg$
+       then (e-write3 'movab `(,(* -4 c) #.np-reg) '#.lbot-reg)
+       else (e-write3 'movab `(,(* -4 c) #.np-reg) '#.lbot-sym)
+           (e-move '#.np-reg '#.np-sym))
+   (e-write3 'calls '$0 (concat "*trantb+" (d-tranloc name)))
+   (if $global-reg$
+       then (e-move '#.lbot-reg '#.np-reg)
+       else (e-write3 'movab `(,(* -4 c) #.np-reg) '#.np-reg)))
+
+#+for-68k
+(defun d-calltran (name c)
+   (if $global-reg$
+       then (e-write3 'lea `(,(* -4 c) #.np-reg) 'a5)
+           (e-move 'a5 '#.lbot-reg)
+       else (e-write3 'lea `(,(* -4 c) #.np-reg) 'a5)
+           (e-move 'a5 '#.lbot-sym)
+           (e-move '#.np-reg '#.np-sym))
+   (e-move (concat "trantb+" (d-tranloc name)) 'a5)
+   (e-quick-call '(0 a5))
+   (if $global-reg$
+       then (e-move '#.lbot-reg '#.np-reg)
+       else (e-write3 'lea `(,(* -4 c) #.np-reg) '#.np-reg)))
+
+;--- d-calldirect :: call a function directly
+;
+;  name - name of a function in the C code (known about by fasl)
+;    c  - number of args
+;
+#+for-vax
+(defun d-calldirect (name c)
+   (if $global-reg$
+       then (e-write3 'movab `(,(* -4 c) #.np-reg) '#.lbot-reg)
+       else (e-write3 'movab `(,(* -4 c) #.np-reg) '#.lbot-sym)
+           (e-move '#.np-reg '#.np-sym))
+   (e-write3 'calls '$0  name)
+   (if $global-reg$
+       then (e-move '#.lbot-reg '#.np-reg)
+       else (e-write3 'movab `(,(* -4 c) #.np-reg) '#.np-reg)))
+
+#+for-68k
+(defun d-calldirect (name c)
+   (if $global-reg$
+       then (e-write3 'lea `(,(* -4 c) #.np-reg) 'a5)
+           (e-move 'a5 '#.lbot-reg)
+       else (e-write3 'lea `(,(* -4 c) #.np-reg) 'a5)
+           (e-move 'a5 '#.lbot-sym)
+           (e-move '#.np-reg '#.np-sym))
+   (e-quick-call name)
+   (if $global-reg$
+       then (e-move '#.lbot-reg '#.np-reg)
+       else (e-write3 'lea `(,(* -4 c) #.np-reg) '#.np-reg)))
+
+;--- d-bcdcall :: call a function through a binary data object
+;  
+; at this point the stack contains n-1 arguments and a binary object which
+; is the address of the compiled lambda expression to go to.  We set
+; up lbot right above the binary on the stack and call the function.
+;
+#+for-vax
+(defun d-bcdcall (n)
+   (if $global-reg$
+       then (e-write3 'movab `(,(* -4 (- n 1)) #.np-reg) '#.lbot-reg)
+       else (e-write3 'movab `(,(* -4 (- n 1)) #.np-reg) '#.lbot-sym)
+           (e-move '#.np-reg '#.np-sym))
+   (e-move  `(* ,(* -4 n) #.np-reg) 'r0)    ;get address to call to
+   (e-write3 'calls '$0 "(r0)")
+   (if $global-reg$
+       then (e-write3 'movab '(-4 #.lbot-reg) '#.np-reg)
+       else (e-write3 'movab `(,(* -4 n) #.np-reg) '#.np-reg)))
+
+#+for-68k
+(defun d-bcdcall (n)
+   (if $global-reg$
+       then (e-write3 'lea `(,(* -4 (- n 1)) #.np-reg) 'a5)
+           (e-move 'a5 '#.lbot-reg)
+       else (e-write3 'lea `(,(* -4 (- n 1)) #.np-reg) 'a5)
+           (e-move 'a5 '#.lbot-sym)
+           (e-move '#.np-reg '#.np-sym))
+   (e-move `(,(* -4 n) #.np-reg) 'a5)  ; get address to call to
+   (e-move `(0 a5) 'a5)
+   (e-quick-call '(0 a5))
+   (if $global-reg$
+       then (e-move '#.lbot-reg 'a5)
+           (e-write3 'lea '(-4 a5) '#.np-reg)
+       else (e-write3 'lea `(,(* -4 n) #.np-reg) '#.np-reg)))
+
+;--- d-dotailrecursion :: do tail recursion if possible
+; name - function name we are to call
+; args - arguments to give to function
+;
+; return t iff we were able to do tail recursion
+; We can do tail recursion if:
+;  g-ret is set indicating that the result of this call will be returned
+;       as the value of the function we are compiling
+;  the function we are calling, name, is the same as the function we are
+;       compiling, g-fname
+;  there are no variables shallow bound, since we would have to unbind
+;       them, which may cause problems in the function.
+;
+(defun d-dotailrecursion (name args)
+   (prog (nargs lbot)
+       (if (null (and g-ret
+                     (eq name g-fname)
+                     (do ((loccnt 0)
+                          (ll g-locs (cdr ll)))
+                         ((null ll) (return t))
+                         (if (dtpr (car ll))
+                             then (if (or (eq 'catcherrset (caar ll))
+                                          (greaterp (cdar ll) 0))
+                                      then (return nil))
+                             else (incr loccnt)))))
+          then (return nil))
+
+       (makecomment '(tail merging))
+       (comp-note g-fname ": Tail merging being done: " v-form)
+
+       (setq nargs (length args))
+       
+       ; evalate the arguments, putting them above the arguments to the
+       ; function we are executing...
+       (let ((g-locs g-locs)
+            (g-loccnt g-loccnt))
+          (d-pushargs args))
+
+       (if $global-reg$
+          then (setq lbot #+for-68k 'a5 #+for-vax '#.lbot-reg)
+               #+for-68k (e-move '#.lbot-reg lbot)
+          else (setq lbot #+for-68k 'a5 #+for-vax '#.fixnum-reg)
+               (e-move '#.lbot-sym lbot))
+
+       ; setup lbot-reg to point to the bottom of the original
+       ;args...
+       (if (eq 'lexpr g-ftype)
+          then #+for-vax
+               (e-write4 'ashl '($ 2) '(* -4 #.olbot-reg) lbot)
+               #+for-68k
+               (progn
+                (d-regused 'd6)
+                (e-move '(* -4 #.olbot-reg) 'd6)
+                (e-write3 'asll '($ 2) 'd6)
+                (e-move 'd6 lbot))
+               (e-sub lbot '#.olbot-reg)
+               (e-sub3 '($ 4) '#.olbot-reg lbot)
+          else (e-move '#.olbot-reg lbot))
+
+       ; copy the new args down into the place of the original ones...
+       (do ((i nargs (1- i))
+           (off-top (* nargs -4) (+ off-top 4))
+           (off-bot 0 (+ off-bot 4)))
+          ((zerop i))
+          (e-move `(,off-top #.np-reg) `(,off-bot ,lbot)))
+
+       ; setup np for the coming call...
+       (e-add3 `($ ,(* 4 nargs)) lbot '#.np-reg)
+
+       (e-goto g-topsym)
+       ;return t to indicate that tailrecursion was successful
+       (return t)))
diff --git a/usr/src/ucb/lisp/liszt/fixnum.l b/usr/src/ucb/lisp/liszt/fixnum.l
new file mode 100644 (file)
index 0000000..c64fecd
--- /dev/null
@@ -0,0 +1,535 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file fixnum
+   "$Header: fixnum.l,v 1.14 83/08/28 17:13:38 layer Exp $")
+
+;;; ----       f i x n u m             fixnum compilation
+;;;
+;;;                            -[Fri Aug 26 14:07:53 1983 by layer]-
+
+;  There are a few functions in lisp which are only permitted to take
+; fixnum operands and produce fixnum results.  The compiler recognizes
+; these functions and open codes them.
+;
+
+;--- d-fixnumexp :: compute a fixnum from an expression
+;      x - a lisp expression which must return a fixnum
+;
+; This is an almost equivalent to d-exp, except that
+; 1] it will do clever things if the expression can be open coded in a 
+;    fixnum way.
+; 2] the result must be a fixnum, and is left in r5 unboxed.
+;
+(defun d-fixnumexp (x)
+  (d-fixnumcode (d-fixexpand x)))
+
+
+;--- c-fixnumop :: compute a fixnum result
+;  This is the extry point into this code from d-exp.  The form to evaluate
+; is in v-form.  The only way we could get here is if the car of v-form
+; is a function which we've stated is a fixnum returning function. 
+;
+(defun c-fixnumop nil
+  (d-fixnumexp v-form)
+  (d-fixnumbox))
+
+;--- d-fixnumbox :: rebox a fixnum in r5
+;
+#+for-vax
+(defun d-fixnumbox ()
+   (let (x)
+       (e-write3 'moval (concat "*$5120[" '#.fixnum-reg "]") 'r0)
+       (e-sub3 '($ 1024) '#.fixnum-reg 'r1)
+       (e-write2 'blssu (setq x (d-genlab)))
+       (e-call-qnewint)
+       (e-writel x)
+       (d-clearreg)))
+
+#+for-68k
+(defun d-fixnumbox ()
+   (let (x)
+       (d-regused '#.fixnum-reg)
+       (e-move '#.fixnum-reg 'd0)
+       (e-write3 'asll '($ 2) 'd0)
+       ; add onto the base of the fixnums
+       (e-add (e-cvt '(fixnum 0)) 'd0)
+       (e-move '#.fixnum-reg 'd1) 
+       (e-sub '($ 1024) 'd1)
+       (e-write2 'jcs (setq x (d-genlab)))     ;branch carry set
+       (e-call-qnewint)
+       (e-writel x)
+       (d-clearreg)))
+
+;--- d-fixexpand  :: pass over a fixnum expression doing local optimizations
+; 
+; This code gets the first look at the operands of a fixnum expression.
+; It handles the strange cases, like (+) or (/ 3), and it also insures
+; that constants are folded (or collapsed as we call it here).
+; 
+; things to watch out for:
+; (+ x y z) we can fold x,y,z , likewise in the case of *
+; (- x y z) we can only fold y and z since they are negated but x is not,
+;          likewise for /
+(defun d-fixexpand (x)
+  (prog nil
+       (setq x (d-macroexpand x))
+    loop
+       (if (and (dtpr x) (symbolp (car x)) (get (car x) 'fixop))
+           then (if (memq (car x) '(+ *))
+                    then  (setq x (cons (car x)
+                                        (d-collapse (cdr x) (car x))))
+                    else  (setq x
+                                (cons (car x)
+                                      (cons (cadr x)
+                                            (d-collapse (cddr x) (car x))))))
+                (if (null (cdr x))
+                    then  ; (- or +) => 0 (* or /) => 1
+                        (setq x
+                              (cdr (assq (car x)
+                                         '((+ . 0) (- . 0)
+                                           (* . 1) (/ . 1)))))
+                        (go loop)
+                 elseif (null (cddr x)) then
+                          ; (+ n) => n, (- n) => (- 0 n), (* n) => n,
+                          ; (/ n) => (/ 1 n)
+                         (setq x
+                               (if (memq (car x) '(* +))
+                                   then (cadr x)
+                                elseif (eq (car x) '-)
+                                   then `(- 0 ,(cadr x))
+                                elseif (eq (car x) '/)
+                                   then `(/ 1 ,(cadr x))
+                                   else (comp-err
+                                            "Internal fixexpand error ")))
+                         (go loop)))
+       (return x)))
+
+;--- d-toplevmacroexpand :: expand top level form if macro
+; a singe level of macro expansion is done.  this is a nice general
+; routine and should be used by d-exp.
+;**** out of date **** will be removed soon
+(defun d-toplevmacroexpand (x)
+  (let ((fnbnd (and (dtpr x) (symbolp (car x)) (getd (car x)))))
+       (if (and fnbnd (or (and (bcdp fnbnd) (eq (getdisc fnbnd) 'macro))
+                         (and (dtpr fnbnd) (eq (car fnbnd) 'macro))))
+          then (d-toplevmacroexpand (apply fnbnd x))
+          else x)))
+
+
+;--- d-collapse :: collapse (fold) constants
+; 
+; this is used to reduce the number of operations. since we know that
+; fixnum operations are commutative.
+;
+(defun d-collapse (form op)
+  (let (const res conlist)
+       ; generate list of constants (conlist) and non constants (res)
+       (do ((xx form (cdr xx)))
+          ((null xx))
+          (if (numberp (car xx))
+              then (if (fixp (car xx))
+                       then (setq conlist (cons (car xx) conlist))
+                       else (comp-err "Illegal operand in fixnum op " 
+                                      (car xx)))
+              else (setq res (cons (car xx) res))))
+
+       ; if no constants found thats ok, but if we found some,
+       ; then collapse and return the form with the collapsed constant
+       ; at the end.
+
+       (if (null conlist)
+          then form    ; no change
+          else (setq res (nreverse 
+                (cons (apply (cond ((or (eq op '/) (eq op '*)) 'times)
+                                   (t 'plus)) 
+                             (cons (cond ((or (eq op '/) (eq op '*)) 1)
+                                         (t 0))
+                                   conlist))
+                      res))))))
+
+
+;---- d-fixnumcode :: emit code for prescanned fixnum expression
+;      expr -  a expression which should return an unboxed fixnum value 
+;              in r5.
+;  This function checks if the expression is indeed a guaranteed fixnum 
+; arithmetic expression, and if so , generates code for the operation.
+; If the expression is not a fixnum operation, then a normal evaluation
+; of the cdr of the expression is done, which will grab the fixnum value
+; and put it in r5.
+;
+#+for-vax
+(defun d-fixnumcode (expr)
+  (let ((operator (and (dtpr expr) 
+                      (symbolp (car expr)) 
+                      (get (car expr) 'fixop)))
+       (g-ret nil)
+       tmp)
+       ; the existance of a fixop property on a function says that it is a
+       ; special fixnum only operation.
+       (if (null operator) 
+          then (let ((g-loc '#.fixnum-reg) g-cc) ; non fixnum op, do normal
+                    (d-exp `(cdr ,expr)))      ; eval to get unboxed number
+          else (do ((xx (cdr expr) (cdr xx))   ; fixnum op, scan all args
+                    (lop) (rop) (res) (opnd))
+                   ((null xx))
+                   (setq opnd (car xx))
+                   (if (fixp opnd) 
+                       then (setq rop `(immed ,opnd))
+                    elseif (and (symbolp opnd) 
+                                (setq rop (d-simple `(cdr ,opnd))))
+                           thenret
+                       else (if (and lop (not (eq lop '#.unCstack)))
+                                then (C-push (e-cvt lop))
+                                (setq lop '#.unCstack))
+                            (d-fixnumcode (d-fixexpand opnd))
+                            (setq rop 'r5))
+                   (if (null lop) 
+                       then (if (cdr xx) 
+                                then (setq lop rop)
+                                else (e-move (e-cvt rop) 'r5))
+                       else (if (cdr xx) 
+                                then (setq res '#.Cstack)
+                                else (setq res 'r5))
+                            (if (setq tmp (d-shiftcheck operator rop))
+                                then (e-write4 'ashl 
+                                               (e-cvt (list 'immed tmp))
+                                               (e-cvt lop)
+                                               (e-cvt res))
+                                else (e-write4 operator (e-cvt rop) 
+                                               (e-cvt lop) 
+                                               (e-cvt res)))
+                            (if (cdr xx) 
+                                then (setq lop '#.unCstack)
+                                else (setq lop "r5")))))))
+
+#+for-68k
+(defun d-fixnumcode (expr)
+   (let ((operator (and (dtpr expr)
+                       (symbolp (car expr))
+                       (get (car expr) 'fixop)))
+        (g-ret nil)
+        tmp)
+       ; the existance of a fixop property on a function says that it is a
+       ; special fixnum only operation.
+       (makecomment `(d-fixnumcode ,expr))
+       (if (null operator) 
+          then (let ((g-loc '#.fixnum-reg) g-cc) ; non fixnum op, do normal
+                   (d-exp `(cdr ,expr)))         ; eval to get unboxed number
+               (d-regused '#.fixnum-reg)
+          else (do ((xx (cdr expr) (cdr xx))     ; fixnum op, scan all args
+                    (lop) (rop) (res) (opnd))
+                   ((null xx))
+                   (setq opnd (car xx))
+                   (if (fixp opnd) 
+                       then (setq rop `(immed ,opnd))
+                    elseif (and (symbolp opnd)
+                                (setq rop (d-simple `(cdr ,opnd))))
+                       thenret
+                       else (if (and lop (not (eq lop '#.unCstack)))
+                                then (C-push (e-cvt lop))
+                                     (setq lop '#.unCstack))
+                            (d-fixnumcode (d-fixexpand opnd))
+                            (setq rop '#.fixnum-reg))
+                   (if (null lop) 
+                       then (if (cdr xx) 
+                                then (setq lop rop)
+                                else (e-move
+                                               (e-cvt rop)
+                                               '#.fixnum-reg))
+                       else (if (cdr xx) 
+                                then (setq res '#.Cstack)
+                                else (setq res '#.fixnum-reg))
+                            (if (setq tmp (d-shiftcheck operator rop))
+                                then (d-asll tmp (e-cvt lop) (e-cvt res))
+                                else (e-move (e-cvt lop) 'd0)
+                                     (e-write3 operator (e-cvt rop) 'd0)
+                                     (e-move 'd0 (e-cvt res)))
+                            (if (cdr xx) 
+                                then (setq lop '#.unCstack)
+                                else (setq lop '#.fixnum-reg)))))
+       (makecomment '(d-fixnumcode done))))
+
+;--- d-shiftcheck      :: check if we can shift instead of multiply
+; return t if the operator is a multiply and the operand is an
+; immediate whose value is a power of two.
+(defun d-shiftcheck (operator operand)
+   (and (eq operator #+for-vax 'lmul
+                    #+for-68k 'mull3)
+       (dtpr operand)
+       (eq (car operand) 'immed)
+       (cdr (assoc (cadr operand) arithequiv))))
+
+; this table is incomplete 
+;
+(setq arithequiv '((1 . 0) (2 . 1) (4 . 2) (8 . 3) (16 . 4) (32 . 5)
+                  (64 . 6) (128 . 7) (256 . 8) (512 . 9) (1024 . 10)
+                  (2048 . 11) (4096 . 12) (8192 . 13) (16384 . 14)
+                  (32768 . 15) (65536 . 16) (131072 . 17)))
+
+
+;--- cc-oneplus  :: compile 1+ form                    = cc-oneplus =
+;  1+ increments a fixnum only. We generate code to check if the number
+; to be incremented is a small fixnum less than or equal to 1022.  This
+; check is done by checking the address of the fixnum's box.  If the
+; number is in that range, we just increment the box pointer by 4.
+; otherwise we call we call _qoneplus which does the add and calls
+; _qnewint
+;
+#+for-vax
+(defun cc-oneplus nil
+  (if (null g-loc)
+      then (if (car g-cc) then (e-goto (car g-cc)))
+      else (let ((argloc (d-simple (cadr v-form)))
+                (lab1 (d-genlab))
+                (lab2 (d-genlab)))
+               (if (null argloc) 
+                   then (let ((g-loc 'r0) g-cc g-ret)
+                             (d-exp (cadr v-form)))
+                        (setq argloc 'reg))
+               (e-cmp (e-cvt argloc) '($ #.(+ 5120 (* 4 1022))))
+               (e-write2 'jleq lab1)
+               (if (not (eq argloc 'r0)) then (d-move argloc 'reg))
+               (e-quick-call '_qoneplus)
+               (if (and g-loc (not (eq g-loc 'reg)))
+                   then (d-move 'reg g-loc))
+               (if (car g-cc)
+                   then (e-goto (car g-cc))
+                   else (e-goto lab2))
+               (e-label lab1)
+               (e-add3 '($ 4) (e-cvt argloc) (e-cvt g-loc))
+               (if (car g-cc) then (e-goto (car g-cc)))
+               (e-label lab2))))
+
+#+for-68k
+(defun cc-oneplus nil
+   (if (null g-loc)
+       then (if (car g-cc) then (e-goto (car g-cc)))
+       else (let ((argloc (d-simple (cadr v-form)))
+                 (lab1 (d-genlab))
+                 (lab2 (d-genlab)))
+               (if (null argloc) 
+                   then (let ((g-loc 'areg) g-cc g-ret)
+                            (d-exp (cadr v-form)))
+                        (setq argloc 'areg))
+               ; ($ (+ Fixzero (* 4 1022))
+               (d-cmp argloc '(fixnum 1022))
+               (e-write2 'jle lab1)
+               (if (not (eq argloc 'areg)) then (d-move argloc 'areg))
+               (e-quick-call '_qoneplus)
+               (if (and g-loc (not (eq g-loc 'reg)))
+                   then (d-move 'reg g-loc))
+               (if (car g-cc)
+                   then (e-goto (car g-cc))
+                   else (e-goto lab2))
+               (e-label lab1)
+               (if (not (eq argloc 'reg))
+                   then (d-move argloc 'reg))
+               (e-write3 'addql "#4" 'd0)
+               (if (and g-loc (not (eq g-loc 'reg)))
+                   then (d-move 'reg g-loc))
+               (if (car g-cc) then (e-goto (car g-cc)))
+               (e-label lab2))))
+                       
+
+
+;--- cc-oneminus :: compile the 1- form
+; just like 1+ we check to see if we are decrementing an small fixnum.
+; and if we are we just decrement the pointer to the fixnum and save
+; a call to qinewint.  The valid range of fixnums we can decrement are
+; 1023 to -1023.  This requires two range checks (as opposed to one for 1+).
+;
+#+for-vax
+(defun cc-oneminus nil
+  (if (null g-loc)
+      then (if (car g-cc) then (e-goto (car g-cc)))
+      else (let ((argloc (d-simple (cadr v-form)))
+                (lab1 (d-genlab))
+                (lab2 (d-genlab))
+                (lab3 (d-genlab)))
+               (if (null argloc) 
+                   then (let ((g-loc 'r0) g-cc)
+                             (d-exp (cadr v-form)))
+                        (setq argloc 'reg))
+               (e-cmp (e-cvt argloc) '($ #.(- 5120 (* 4 1024))))
+               (e-write2 'jleq lab1)   ; not within range
+               (e-cmp (e-cvt argloc) '($ #.(+ 5120 (* 4 1023))))
+               (e-write2 'jleq lab2)   ; within range
+               ; not within range, must do it the hard way.
+               (e-label lab1)
+               (if (not (eq argloc 'r0)) then (d-move argloc 'reg))
+               (e-quick-call '_qoneminus)
+               (if (and g-loc (not (eq g-loc 'reg)))
+                   then (d-move 'reg g-loc))
+               (if (car g-cc)
+                   then (e-goto (car g-cc))
+                   else (e-goto lab3))
+               (e-label lab2)
+               ; we are within range, just decrement the pointer by the
+               ; size of a word (4 bytes).
+               (e-sub3 '($ 4) (e-cvt argloc) (e-cvt g-loc))
+               (if (car g-cc) then (e-goto (car g-cc)))
+               (e-label lab3))))
+
+#+for-68k
+(defun cc-oneminus nil
+  (if (null g-loc)
+      then (if (car g-cc) then (e-goto (car g-cc)))
+      else (let ((argloc (d-simple (cadr v-form)))
+                (lab1 (d-genlab))
+                (lab2 (d-genlab))
+                (lab3 (d-genlab)))
+               (if (null argloc) 
+                   then (let ((g-loc 'areg) g-cc)
+                             (d-exp (cadr v-form)))
+                        (setq argloc 'areg))
+               ; ($ (- Fixzero (* 4 1024)))
+               (d-cmp argloc '(fixnum -1024))
+               (e-write2 'jle lab1)    ; not within range
+               (d-cmp argloc '(fixnum 1023))
+               (e-write2 'jle lab2)    ; within range
+               ; not within range, must do it the hard way.
+               (e-label lab1)
+               (if (not (eq argloc 'areg)) then (d-move argloc 'areg))
+               (e-quick-call '_qoneminus)
+               (if (and g-loc (not (eq g-loc 'reg)))
+                   then (d-move 'reg g-loc))
+               (if (car g-cc)
+                   then (e-goto (car g-cc))
+                   else (e-goto lab3))
+               (e-label lab2)
+               ; we are within range, just decrement the pointer by the
+               ; size of a word (4 bytes).
+               (if (not (eq argloc 'reg))
+                   then (d-move argloc 'reg))
+               (e-sub '($ 4) 'd0)
+               (if (and g-loc (not (eq g-loc 'reg)))
+                   then (d-move 'reg g-loc))
+               (if (car g-cc) then (e-goto (car g-cc)))
+               (e-label lab3))))
+
+;--- cm-<  :: compile a < expression
+; 
+; the operands to this form can either be fixnum or flonums but they
+; must be of the same type.
+;
+; We can compile the form just like an eq form since all we want is
+; a compare and a jump.  The comparisons are inverted since that is
+; the way eq expects it.
+
+(defun cm-< nil
+   (if (not (= 2 (length (cdr v-form))))
+      then (comp-err "incorrect number of arguments to < " v-form))
+   ; only can do fixnum stuff if we know that one of the args is
+   ; a fixnum.
+   ;
+   (if (or (fixp (cadr v-form)) (fixp (caddr v-form)))
+      then `(<& ,(cadr v-form) ,(caddr v-form))
+      else `(lessp ,(cadr v-form) ,(caddr v-form))))
+
+;--- c-<& :: fixnum <
+;
+; We can compile the form just like an eq form since all we want is
+; a compare and a jump.  The comparisons are inverted since that is
+; the way eq expects it.
+
+(defun cc-<& nil
+   (let ((g-trueop  #+for-vax 'jgeq #+for-68k 'jpl)
+        (g-falseop #+for-vax 'jlss #+for-68k 'jmi)
+        (v-form `(eq (cdr ,(cadr v-form)) (cdr ,(caddr v-form)))))
+      (cc-eq)))
+
+;--- cm->  :: compile a > expression
+;
+; the operands to this form can either be fixnum or flonums but they
+; must be of the same type.  
+; We can compile the form just like an eq form since all we want is
+; a compare and a jump.  The comparisons are inverted since that is
+; the way eq expects it.
+(defun cm-> nil
+   (if (not (= 2 (length (cdr v-form))))
+      then (comp-err "incorrect number of arguments to > " v-form))
+   ; only can do fixnum stuff if we know that one of the args is
+   ; a fixnum.
+   ;
+   (if (or (fixp (cadr v-form)) (fixp (caddr v-form)))
+      then `(>& ,(cadr v-form) ,(caddr v-form))
+      else `(greaterp ,(cadr v-form) ,(caddr v-form))))
+
+;--- cc->& :: compile a fixnum > function
+;
+; We can compile the form just like an eq form since all we want is
+; a compare and a jump.  The comparisons are inverted since that is
+; the way eq expects it.
+(defun cc->& nil
+   (let ((g-trueop  #+for-vax 'jleq #+for-68k 'jle)
+        (g-falseop #+for-vax 'jgtr #+for-68k 'jgt)
+        (v-form `(eq (cdr ,(cadr v-form)) (cdr ,(caddr v-form)))))
+      (cc-eq)))
+
+;--- cm-=  : compile an = expression
+;  The = function is a strange one.  It can compare two fixnums or two
+; flonums which is fine on a pdp-10 where they are the same size, but
+; is a real pain on a vax where they are different sizes.
+; We thus can see if one of the arguments is a fixnum and assume that
+; the other one is and then  call =&, the fixnum equal code.
+;
+(defun cm-= nil
+   (if (not (= 2 (length (cdr v-form))))
+      then (comp-err "incorrect number of arguments to = : " v-form))
+   (if (or (fixp (cadr v-form)) (fixp (caddr v-form)))
+      then `(=& ,(cadr v-form) ,(caddr v-form))
+      else `(equal ,(cadr v-form) ,(caddr v-form))))
+
+;--- cm-=&
+;
+; if the number is within the small fixnum range, we can just
+; do pointer comparisons.
+;
+(defun cm-=& nil
+   (if (or (and (fixp (cadr v-form))
+               (< (cadr v-form) 1024)
+               (> (cadr v-form) -1025))
+          (and (fixp (caddr v-form))
+               (< (caddr v-form) 1024)
+               (> (caddr v-form) -1025)))
+      then `(eq ,(cadr v-form) ,(caddr v-form))
+      else `(eq (cdr ,(cadr v-form)) (cdr ,(caddr v-form)))))
+
+; this should be converted
+#+for-vax
+(defun c-\\ nil
+   (d-fixop 'ediv  'remainder))
+
+#+for-vax
+(defun d-fixop (opcode lispopcode)
+   (prog (op1 op2 rop1 rop2 simpleop1)
+       (if (not (eq 3 (length v-form))) ; only handle two ops for now
+          then (d-callbig lispopcode (cdr v-form) nil)
+          else (setq op1 (cadr v-form)
+                     op2 (caddr v-form))
+               (if (fixp op1)
+                   then (setq rop1 `($ ,op1)  ; simple int
+                              simpleop1 t)         
+                   else (if (setq rop1 (d-simple `(cdr ,op1)))
+                            then (setq rop1 (e-cvt rop1))
+                            else (let ((g-loc 'reg) g-cc g-ret)
+                                     (d-exp op1))
+                                 (setq rop1 '(0 r0))))
+               (if (fixp op2)
+                   then (setq rop2 `($ ,op2))
+                   else (if (setq rop2 (d-simple `(cdr ,op2)))
+                            then (setq rop2 (e-cvt rop2))
+                            else (C-push rop1)
+                                 (setq rop1 '#.unCstack)
+                                 (let ((g-loc 'reg)
+                                       g-cc g-ret)
+                                     (d-exp op2))
+                                 (setq rop2 '(0 r0))))
+               (if (eq opcode 'ediv)
+                   then (if (not simpleop1)
+                            then (e-move rop1 'r2)  ; need quad
+                                 (e-write4 'ashq '$-32 'r1 'r1)
+                                 (setq rop1 'r1))      ; word div.
+                        (e-write5 'ediv rop2 rop1 'r0 'r5)
+                   else (e-write4 opcode rop2 rop1 'r5))
+               (d-fixnumbox)
+               (d-clearreg))))
diff --git a/usr/src/ucb/lisp/liszt/funa.l b/usr/src/ucb/lisp/liszt/funa.l
new file mode 100644 (file)
index 0000000..86a7dfe
--- /dev/null
@@ -0,0 +1,930 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file funa
+   "$Header: funa.l,v 1.11 83/08/28 17:14:35 layer Exp $")
+
+;;; ----       f u n a                         function compilation
+;;;
+;;;                            -[Mon Aug 22 22:01:01 1983 by layer]-
+
+
+;--- cc-and :: compile an and expression
+; We evaluate forms from left to right as long as they evaluate to
+; a non nil value.  We only have to worry about storing the value of
+; the last expression in g-loc.
+;
+(defun cc-and nil
+  (let ((finlab (d-genlab))
+       (finlab2)
+       (exps (if (cdr v-form) thenret else '(t))))     ; (and) ==> t
+       (if (null (cdr g-cc))
+          then (d-exp (do ((g-cc (cons nil finlab))
+                           (g-loc)
+                           (g-ret)
+                           (ll exps (cdr ll)))
+                          ((null (cdr ll)) (car ll))
+                          (d-exp (car ll))))
+               (if g-loc
+                   then (setq finlab2 (d-genlab))
+                        (e-goto finlab2)
+                        (e-label finlab)
+                        (d-move 'Nil g-loc)
+                        (e-label finlab2)
+                   else (e-label finlab))
+          else ;--- cdr g-cc is non nil, thus there is
+               ; a quick escape possible if one of the
+               ; expressions evals to nil
+
+               (if (null g-loc) then (setq finlab (cdr g-cc)))
+               (d-exp (do ((g-cc (cons nil finlab))
+                           (g-loc)
+                           (g-ret)
+                           (ll exps (cdr ll)))
+                          ((null (cdr ll)) (car ll))
+                          (d-exp (car ll))))
+               ; if g-loc is non nil, then we have evaled the and
+               ; expression to yield nil, which we must store in
+               ; g-loc and then jump to where the cdr of g-cc takes us
+               (if g-loc
+                   then (setq finlab2 (d-genlab))
+                        (e-goto finlab2)
+                        (e-label finlab)
+                        (d-move 'Nil g-loc)
+                        (e-goto (cdr g-cc))
+                        (e-label finlab2))))
+  (d-clearreg))         ; we cannot predict the state of the registers
+
+;--- cc-arg  :: get the nth arg from the current lexpr
+;
+; the syntax for Franz lisp is (arg i)
+; for interlisp the syntax is (arg x i) where x is not evaluated and is
+; the name of the variable bound to the number of args.  We can only handle
+; the case of x being the variable for the current lexpr we are compiling
+;
+(defun cc-arg nil
+   (prog (nillab finlab)
+       (setq nillab (d-genlab)
+            finlab (d-genlab))
+       (if (not (eq 'lexpr g-ftype)) 
+          then (comp-err " arg only allowed in lexprs"))
+       (if (and (eq (length (cdr v-form)) 2) fl-inter)
+          then (if (not (eq (car g-args) (cadr v-form)))
+                   then (comp-err " arg expression is for non local lexpr "
+                                  v-form)
+                   else (setq v-form (cdr v-form))))
+       (if (and (null g-loc) (null g-cc))
+          then ;bye bye, wouldn't do anything
+               (return nil))
+       (if (and (fixp (cadr v-form)) (>& (cadr v-form) 0))
+          then ; simple case (arg n) for positive n
+               (d-move `(fixnum ,(cadr v-form)) 'reg)
+               #+for-68k
+               (progn
+                   (e-sub `(-4 #.olbot-reg) 'd0)
+                   (if g-loc
+                       then (e-move '(% -8 #.olbot-reg d0) (e-cvt g-loc)))
+                   (if g-cc then (e-cmpnil '(% -8 #.olbot-reg d0))))
+               #+for-vax
+               (progn
+                   (e-sub3 '(* -4 #.olbot-reg) '(0 r0) 'r0)
+                   (if g-loc
+                       then (e-move '(-8 #.olbot-reg r0) (e-cvt g-loc))
+                    elseif g-cc
+                       then (e-tst '(-8 #.olbot-reg r0))))
+               (d-handlecc)
+       elseif (or (null (cadr v-form))
+                  (and (fixp (cadr v-form)) (=& 0 (cadr v-form))))
+          then ;---the form is: (arg nil) or (arg) or (arg 0).
+               ;   We have a private copy of the number of args right
+               ; above the arguments on the name stack, so that
+               ; the user can't clobber it... (0 olbot) points
+               ; to the user setable copy, and (-4 olbot) to our
+               ; copy.
+               (if g-loc then (e-move '(-4 #.olbot-reg) (e-cvt g-loc)))
+               ;   Will always return a non nil value, so
+               ; don't even test it.
+               (if (car g-cc) then (e-goto (car g-cc)))
+          else ; general (arg <form>)
+               (let ((g-loc 'reg)
+                     (g-cc (cons nil nillab))
+                     (g-ret))
+                   (d-exp (cadr v-form)))  ;boxed fixnum or nil
+               ; (arg 0) returns nargs (compiler only!)
+               (d-cmp 'reg '(fixnum 0))
+               (e-gotonil nillab)
+               
+               ; ... here we are doing (arg <number>), <number> != 0
+               #+for-68k
+               (progn
+                   (e-sub '(-4 #.olbot-reg) 'd0)
+                   (if g-loc
+                       then (e-move '(% -8 #.olbot-reg d0) (e-cvt g-loc)))
+                   (if g-cc then (e-cmpnil '(% -8 #.olbot-reg d0))))
+               #+for-vax
+               (progn
+                   (e-sub3 `(* -4 #.olbot-reg) '(0 r0) 'r0)
+                   (if g-loc
+                       then (e-move '(-8 #.olbot-reg r0) (e-cvt g-loc))
+                    elseif g-cc
+                       then (e-tst '(-8 #.olbot-reg r0))))
+               (d-handlecc)
+               (e-goto finlab)
+               (e-label nillab)
+               ; here we are doing (arg nil) which
+               ; returns the number of args
+               ; which is always true if anyone is testing
+               (if g-loc
+                   then (e-move '(-4 #.olbot-reg) (e-cvt g-loc))
+                        #+for-68k (if g-cc then (e-cmpnil '(-4 #.olbot-reg)))
+                        (d-handlecc)
+                elseif (car g-cc)
+                   then (e-goto (car g-cc))) ;always true
+               (e-label finlab))))
+
+;--- c-assembler-code
+; the args to assembler-code are a list of assembler language 
+; statements.  This statements are put directly in the code
+; stream produced by the compiler.  Beware: The interpreter cannot
+; interpret the assembler-code function.
+;
+(defun c-assembler-code nil
+  (setq g-skipcode nil)                ; turn off code skipping
+  (makecomment '(assembler code start))
+  (do ((xx (cdr v-form) (cdr xx)))
+      ((null xx))
+      (e-write1 (car xx)))
+  (makecomment '(assembler code end)))
+
+;--- cm-assq :: assoc with eq for testing
+;
+; form: (assq val list)
+;
+(defun cm-assq nil
+  `(do ((xx-val ,(cadr v-form))
+       (xx-lis ,(caddr v-form) (cdr xx-lis)))
+       ((null xx-lis))
+       (cond ((eq xx-val (caar xx-lis)) (return (car xx-lis))))))
+
+;--- cc-atom :: test for atomness
+;
+(defun cc-atom nil
+  (d-typecmplx (cadr v-form)
+              #.(immed-const (plus 1_0 1_1 1_2 1_4 1_5 1_6 1_7 1_9 1_10))))
+
+;--- c-bcdcall :: do a bcd call
+;
+; a bcdcall is the franz equivalent of the maclisp subrcall.
+; it is called with
+; (bcdcall 'b_obj 'arg1 ...)
+;  where b_obj must be a binary object. no type checking is done.
+;
+(defun c-bcdcall nil
+  (d-callbig 1 (cdr v-form) t))
+
+;--- cc-bcdp :: check for bcdpness
+;
+(defun cc-bcdp nil
+  (d-typesimp (cadr v-form) #.(immed-const 5)))
+
+;--- cc-bigp :: check for bignumness
+;
+(defun cc-bigp nil
+  (d-typesimp (cadr v-form) #.(immed-const 9)))
+
+;--- c-boole :: compile
+;
+#+for-vax
+(progn 'compile
+(defun c-boole nil
+   (cond ((fixp (cadr v-form))
+         (setq v-form (d-boolexlate (d-booleexpand v-form)))))
+   (cond ((eq 'boole (car v-form))     ;; avoid recursive calls to d-exp
+         (d-callbig 'boole (cdr v-form) nil))
+        (t (let ((g-loc 'reg) (g-cc nil) (g-ret nil))  ; eval answer
+              (d-exp v-form)))))
+
+;--- d-booleexpand :: make sure boole only has three args
+;  we use the identity (boole k x y z) == (boole k (boole k x y) z)
+; to make sure that there are exactly three args to a call to boole
+;
+(defun d-booleexpand (form)
+   (if (and (dtpr form) (eq 'boole (car form)))
+       then (if (< (length form) 4)
+               then (comp-err "Too few args to boole : " form)
+            elseif (= (length form) 4)
+               then form
+               else (d-booleexpand
+                        `(boole ,(cadr form)
+                                 (boole ,(cadr form)
+                                         ,(caddr form)
+                                         ,(cadddr form))
+                                 ,@(cddddr form))))
+       else form))
+
+(declare (special x y))
+(defun d-boolexlate (form)
+   (if (atom form)
+       then form
+    elseif (and (eq 'boole (car form))
+               (fixp (cadr form)))
+       then (let ((key (cadr form))
+                 (x (d-boolexlate (caddr form)))
+                 (y (d-boolexlate (cadddr form)))
+                 (res))
+               (makecomment `(boole key = ,key))
+               (if (eq key 0)          ;; 0
+                   then `(progn ,x ,y 0)
+                elseif (eq key 1)      ;; x * y
+                   then `(fixnum-BitAndNot ,x (fixnum-BitXor ,y -1))
+                elseif (eq key 2)      ;; !x * y
+                   then `(fixnum-BitAndNot (fixnum-BitXor ,x -1)
+                                           (fixnum-BitXor ,y -1))
+                elseif (eq key 3)      ;; y
+                   then `(progn ,x ,y)
+                elseif (eq key 4)      ;; x * !y
+                   then `(fixnum-BitAndNot ,x ,y)
+                elseif (eq key 5)      ;; x
+                   then `(prog1 ,x ,y)
+                elseif (eq key 6)        ;; x xor y
+                   then `(fixnum-BitXor ,x ,y)
+                elseif (eq key 7)      ;; x + y
+                   then `(fixnum-BitOr ,x ,y)
+                elseif (eq key 8)      ;; !(x xor y)
+                   then `(fixnum-BitXor (fixnum-BitOr ,x ,y) -1)
+                elseif (eq key 9)      ;; !(x xor y)
+                   then `(fixnum-BitXor (fixnum-BitXor ,x ,y) -1)
+                elseif (eq key 10)     ;; !x
+                   then `(prog1 (fixnum-BitXor ,x -1) ,y)
+                elseif (eq key 11)     ;; !x + y
+                   then `(fixnum-BitOr (fixnum-BitXor ,x -1) ,y)
+                elseif (eq key 12)     ;; !y
+                   then `(progn ,x (fixnum-BitXor ,y -1))
+                elseif (eq key 13)     ;; x + !y
+                   then `(fixnum-BitOr ,x (fixnum-BitXor ,y -1))
+                elseif (eq key 14)     ;; !x + !y
+                   then `(fixnum-BitOr (fixnum-BitXor ,x -1)
+                                       (fixnum-BitXor ,y -1))
+                elseif (eq key 15)     ;; -1
+                   then `(progn ,x ,y -1)
+                   else form))
+       else form))
+
+(declare (unspecial x y))
+) ;; end for-vax
+
+
+;--- c-*catch :: compile a *catch expression
+;
+; the form of *catch is (*catch 'tag 'val)
+; we evaluate 'tag and set up a catch frame, and then eval 'val
+;
+(defun c-*catch nil
+   (let ((g-loc 'reg)
+        (g-cc nil)
+        (g-ret nil)
+        (finlab (d-genlab))
+        (beglab (d-genlab)))
+       (d-exp (cadr v-form))           ; calculate tag into 'reg
+       (d-pushframe #.F_CATCH 'reg 'Nil) ; the Nil is a don't care
+       (push nil g-labs)               ; disallow labels
+       ; retval will be non 0 if we were thrown to, in which case the value
+       ; thrown is in _lispretval.
+       ; If we weren't thrown-to the value should be calculated in r0.
+       (e-tst '_retval)
+       (e-write2 #+for-vax 'jeql #+for-68k 'jeq beglab)
+       (e-move '_lispretval (e-cvt 'reg))
+       (e-write2 #+for-vax 'jbr #+for-68k 'jra finlab)
+       (e-label beglab)
+       (d-exp (caddr v-form))
+       (e-label finlab)
+       (d-popframe)    ; remove catch frame from stack
+       (unpush g-locs) ; remove (catcherrset . 0)
+       (unpush g-labs)  ; allow labels again
+       (d-clearreg)))
+
+;--- d-pushframe :: put an evaluation frame on the stack
+;
+; This is equivalant in the C system to 'errp = Pushframe(class,arg1,arg2);'
+; We stack a frame which describes the class (will always be F_CATCH)
+; and the other option args.
+; 2/10/82 - it is a bad idea to stack a variable number of arguments, since
+; this makes it more complicated to unstack frames.  Thus we will always
+; stack the maximum --jkf
+(defun d-pushframe (class arg1 arg2)
+  (C-push (e-cvt arg2))
+  (C-push (e-cvt arg1))
+  (C-push `($ ,class))
+  (if (null $global-reg$)
+      then (e-move '#.np-reg '#.np-sym)
+          (e-move '#.np-reg '#.lbot-sym))
+  (e-quick-call '_qpushframe)
+  (e-move (e-cvt 'reg) '_errp)
+  (push '(catcherrset . 0) g-locs))
+
+;--- d-popframe :: remove an evaluation frame from the stack
+;
+; This is equivalent in the C system to 'errp = Popframe();'
+;  n is the number of arguments given to the pushframe which
+; created this frame.  We have to totally remove this frame from
+; the stack only if we are in a local function, but for now, we just
+; do it all the time.
+;
+(defun d-popframe ()
+   (let ((treg #+for-vax 'r1 #+for-68k 'a5))
+       (e-move '_errp treg)
+       (e-move `(#.OF_olderrp ,treg) '_errp)
+       ; there are always 3 arguments pushed, and the frame contains 5
+       ; longwords.  We should make these parameters into manifest
+       ; constants --jkf
+       (e-add3 `($ ,(+ (* 3 4) (* 5 4))) treg 'sp)))
+
+;--- c-cond :: compile a "cond" expression
+;
+; not that this version of cond is a 'c' rather than a 'cc' . 
+; this was done to make coding this routine easier and because
+; it is believed that it wont harm things much if at all
+;
+(defun c-cond nil
+  (makecomment '(beginning cond))
+  (do ((clau (cdr v-form) (cdr clau))
+       (finlab (d-genlab))
+       (nxtlab)
+       (save-reguse)
+       (seent))
+      ((or (null clau) seent)
+       ; end of cond
+       ; if haven't seen a t must store a nil in `reg'
+       (if (null seent)  then (d-move 'Nil 'reg))
+       (e-label finlab))
+
+      ; case 1 - expr
+      (if (atom (car clau))
+         then (comp-err "bad cond clause " (car clau))
+      ; case 2 - (expr)
+       elseif (null (cdar clau))
+         then (let ((g-loc (if (or g-cc g-loc) then 'reg))
+                    (g-cc (cons finlab nil))
+                    (g-ret (and g-ret (null (cdr clau)))))
+                   (d-exp (caar clau)))
+      ; case 3 - (t expr1 expr2 ...)
+       elseif (or (eq t (caar clau))
+                 (equal ''t (caar clau)))
+         then (let ((g-loc (if (or g-cc g-loc) then 'reg))
+                    g-cc)
+                   (d-exps (cdar clau)))
+              (setq seent t)
+      ; case 4 - (expr1 expr2 ...)
+       else (let ((g-loc nil)
+                 (g-cc (cons nil (setq nxtlab (d-genlab))))
+                 (g-ret nil))
+                (d-exp (caar clau)))
+           (setq save-reguse (copy g-reguse))
+           (let ((g-loc (if (or g-cc g-loc) then 'reg))
+                 g-cc)
+                (d-exps (cdar clau)))
+           (if (or (cdr clau) (null seent)) then (e-goto finlab))
+           (e-label nxtlab)
+           (setq g-reguse save-reguse)))
+  
+  (d-clearreg))
+             
+;--- c-cons :: do a cons instruction quickly
+;
+(defun c-cons nil
+  (d-pushargs (cdr v-form))            ; there better be 2 args
+  (e-quick-call '_qcons)
+  (setq g-locs (cddr g-locs))
+  (setq g-loccnt (- g-loccnt 2))
+  (d-clearreg))
+
+;--- c-cxr :: compile a cxr instruction
+; 
+;
+(defun cc-cxr nil
+  (d-supercxr t nil))
+
+;--- d-supercxr :: do a general struture reference
+;      type - one of fixnum-block,flonum-block,<other-symbol>
+; the type is that of an array, so <other-symbol> could be t, nil
+; or anything else, since anything except *-block is treated the same
+;
+; the form of a cxr is (cxr index hunk) but supercxr will handle
+; arrays too, so hunk could be (getdata (getd 'arrayname))
+;
+; offsetonly is t if we only care about the offset of this element from
+; the beginning of the data structure.  If offsetonly is t then type
+; will be nil.
+;
+; Note: this takes care of g-loc and g-cc 
+
+#+for-vax
+(defun d-supercxr (type offsetonly)
+  (let ((arg1 (cadr v-form))
+       (arg2 (caddr v-form))
+       lop rop semisimple)
+
+       (if (fixp arg1) then (setq lop `(immed ,arg1))
+          else (d-fixnumexp arg1)      ; calculate index into r5
+               (setq lop 'r5))         ; and remember that it is there
+
+       ; before we calculate the second expression, we may have to save
+       ; the value just calculated into r5.  To be safe we stack away
+       ; r5 if the expression is not simple or semisimple.
+       (if (not (setq rop (d-simple arg2)))    
+          then (if (and (eq lop 'r5) 
+                        (not (setq semisimple (d-semisimple arg2))))
+                   then (C-push (e-cvt lop)))
+               (let ((g-loc 'reg) g-cc)
+                    (d-exp arg2))
+               (setq rop 'r0)
+
+               (if (and (eq lop 'r5) (not semisimple))
+                   then (C-pop (e-cvt lop))))
+
+       (if (eq type 'flonum-block)
+         then (setq lop (d-structgen lop rop 8))
+              (e-write3 'movq lop 'r4)
+              (e-quick-call '_qnewdoub)        ; box number
+              (d-clearreg)                     ; clobbers all regs
+              (if (and g-loc (not (eq g-loc 'reg)))
+                 then (d-move 'reg g-loc))
+              (if (car g-cc) then (e-goto (car g-cc)))
+         else (setq lop (d-structgen lop rop 4)
+                    rop (if g-loc then
+                            (if (eq type 'fixnum-block) then 'r5 
+                               else (e-cvt g-loc))))
+              (if rop 
+                 then (if offsetonly
+                         then (e-write3 'moval lop rop)
+                         else (e-move lop rop))
+                      (if (eq type 'fixnum-block) 
+                          then (e-call-qnewint)
+                               (d-clearreg)
+                               (if (not (eq g-loc 'reg))
+                                   then (d-move 'reg g-loc))
+                               ; result is always non nil.
+                               (if (car g-cc) then (e-goto (car g-cc)))
+                          else (d-handlecc))
+               elseif g-cc 
+                 then (if (eq type 'fixnum-block)
+                         then (if (car g-cc) 
+                                 then (e-goto (car g-cc)))
+                         else (e-tst lop)
+                               (d-handlecc))))))
+
+#+for-68k
+(defun d-supercxr (type offsetonly)
+   (let ((arg1 (cadr v-form))
+        (arg2 (caddr v-form))
+        lop rop semisimple)
+       (makecomment `(Starting d-supercxr: vform: ,v-form))
+       (if (fixp arg1) then (setq lop `(immed ,arg1))
+          else (d-fixnumexp arg1)        ; calculate index into fixnum-reg
+               (d-regused '#.fixnum-reg)
+               (setq lop '#.fixnum-reg)) ; and remember that it is there
+       ;
+       ; before we calculate the second expression, we may have to save
+       ; the value just calculated into fixnum-reg. To be safe we stack away
+       ; fixnum-reg if the expression is not simple or semisimple.
+       (if (not (setq rop (d-simple arg2)))    
+          then (if (and (eq lop '#.fixnum-reg)
+                        (not (setq semisimple (d-semisimple arg2))))
+                   then (C-push (e-cvt lop)))
+               (let ((g-loc 'areg) g-cc)
+                   (d-exp arg2))
+               (setq rop 'a0)
+               ;
+               (if (and (eq lop '#.fixnum-reg) (not semisimple))
+                   then (C-pop (e-cvt lop))))
+       ;
+       (if (eq type 'flonum-block)
+          then (setq lop (d-structgen lop rop 8))
+               (break " d-supercxr : flonum stuff not done.")
+               (e-write3 'movq lop 'r4)
+               (e-quick-call '_qnewdoub)       ; box number
+               (d-clearreg)                    ; clobbers all regs
+               (if (and g-loc (not (eq g-loc 'areg)))
+                   then (d-move 'areg g-loc))
+               (if (car g-cc) then (e-goto (car g-cc)))
+          else (if (and (dtpr rop) (eq 'stack (car rop)))
+                   then (e-move (e-cvt rop) 'a1)
+                        (setq rop 'a1))
+               (setq lop (d-structgen lop rop 4)
+                     rop (if g-loc then
+                             (if (eq type 'fixnum-block)
+                                 then '#.fixnum-reg 
+                                 else (e-cvt g-loc))))
+               (if rop 
+                   then (if offsetonly
+                            then (e-write3 'lea lop 'a5)
+                                 (e-move 'a5 rop)
+                            else (e-move lop rop))
+                        (if (eq type 'fixnum-block) 
+                            then (e-call-qnewint)
+                                 (d-clearreg)
+                                 (if (not (eq g-loc 'areg))
+                                     then (d-move 'areg g-loc))
+                                 ; result is always non nil.
+                                 (if (car g-cc) then (e-goto (car g-cc)))
+                            else (e-cmpnil lop)
+                                 (d-handlecc))
+                elseif g-cc 
+                   then (if (eq type 'fixnum-block)
+                            then (if (car g-cc) 
+                                     then (e-goto (car g-cc)))
+                            else (if g-cc
+                                     then (e-cmpnil lop)
+                                          (d-handlecc)))))
+       (makecomment "Done with d-supercxr")))
+
+;--- d-semisimple :: check if result is simple enough not to clobber r5
+; currently we look for the case of (getdata (getd 'foo))
+; since we know that this will only be references to r0.
+; More knowledge can be added to this routine.
+;
+(defun d-semisimple (form)
+  (or (d-simple form)
+      (and (dtpr form) 
+          (eq 'getdata (car form))
+          (dtpr (cadr form))
+          (eq 'getd (caadr form))
+          (dtpr (cadadr form))
+          (eq 'quote (caadadr form)))))
+
+;--- d-structgen :: generate appropriate address for indexed access
+;      index - index address, must be (immed n) or r5 (which contains int)
+;      base  - address of base
+;      width - width of data element
+; want to calculate appropriate address for base[index]
+; may require emitting instructions to set up registers
+; returns the address of the base[index] suitable for setting or reading
+;
+; the code sees the base as a stack value as a special case since it
+; can generate (perhaps) better code for that case.
+
+#+for-vax
+(defun d-structgen (index base width)
+  (if (and (dtpr base) (eq (car base) 'stack))
+      then (if (dtpr index)    ; i.e if index = (immed n)
+              then (d-move index 'r5)) ; get immed in register
+          ;  the result is always *n(r6)[r5]
+          (append (e-cvt `(vstack ,(cadr base))) '(r5))
+      else (if (not (atom base))       ; i.e if base is not register
+              then (d-move base 'r0)   ; (if nil gets here we will fail)
+                   (d-clearreg 'r0)
+                   (setq base 'r0))
+          (if (dtpr index) then `(,(* width (cadr index)) ;immed index
+                                   ,base)
+                           else `(0 ,base r5))))
+
+#+for-68k
+(defun d-structgen (index base width)
+   (if (and (dtpr base) (eq (car base) 'stack))
+       then (break "d-structgen: bad args(1)")
+       else (if (not (atom base))      ; i.e if base is not register
+               then (d-move base 'a0)  ; (if nil gets here we will fail)
+                    (d-clearreg 'a0)
+                    (setq base 'a0))
+           (if (dtpr index)
+               then `(,(* width (cadr index)) ,base)
+               else (d-regused 'd6)
+                    (e-move index 'd6)
+                    (e-write3 'asll '($ 2) 'd6)
+                    `(% 0 ,base d6))))
+
+;--- c-rplacx :: complile a rplacx expression
+;
+;  This simple calls the general structure hacking function, d-superrplacx
+;  The argument, hunk, means that the elements stored in the hunk are not
+;  fixum-block or flonum-block arrays.
+(defun c-rplacx nil
+  (d-superrplacx 'hunk))
+
+;--- d-superrplacx :: handle general setting of things in structures
+;      type - one of fixnum-block, flonum-block, hunk
+; see d-supercxr for comments
+; form of rplacx is (rplacx index hunk valuetostore)
+#+for-vax
+(defun d-superrplacx (type)
+        (let ((arg1 (cadr v-form))
+              (arg2 (caddr v-form))
+              (arg3 (cadddr v-form))
+              lop rop semisimple)
+             
+             ; calulate index and put it in r5 if it is not an immediate
+             ; set lop to the location of the index
+             (if (fixp arg1) then (setq lop `(immed ,arg1))
+                 else (d-fixnumexp arg1)
+                      (setq lop 'r5))  
+             
+             ; set rop to the location of the hunk.  If we have to 
+             ; calculate the hunk, we may have to save r5.
+             ; If we are doing a rplacx (type equals hunk) then we must
+             ; return the hunk in r0.
+             (if (or (eq type 'hunk) (not (setq rop (d-simple arg2))))
+                 then (if (and (eq lop 'r5) 
+                               (not (setq semisimple (d-semisimple arg2))))
+                          then (d-move lop '#.Cstack))
+                      (let ((g-loc 'r0) g-cc)
+                           (d-exp arg2))
+                      (setq rop 'r0)
+                 
+                      (if (and (eq lop 'r5) (not semisimple))
+                          then (d-move '#.unCstack lop)))
+
+             ; now that the index and data block locations are known, we 
+             ; caclulate the location of the index'th element of hunk
+             (setq rop
+                   (d-structgen lop rop
+                                (if (eq type 'flonum-block) then 8 else 4)))
+
+             ; the code to calculate the value to store and the actual
+             ; storing depends on the type of data block we are storing in.
+             (if (eq type 'flonum-block) 
+                 then (if (setq lop (d-simple `(cdr ,arg3)))
+                          then (e-write3 'movq (e-cvt lop) rop)
+                          else ; preserve rop since it may be destroyed
+                               ; when arg3 is calculated
+                               (e-write3 'movaq rop '#.Cstack)
+                               (let ((g-loc 'r0) g-cc)
+                                    (d-exp arg3))
+                               (d-clearreg 'r0)
+                               (e-write3 'movq '(0 r0) "*(sp)+"))
+              elseif (and (eq type 'fixnum-block)
+                          (setq arg3 `(cdr ,arg3))
+                          nil)
+                     ; fixnum-block is like hunk except we must grab the
+                     ; fixnum value out of its box, hence the (cdr arg3)
+                  thenret
+              else (if (setq lop (d-simple arg3))
+                       then (e-move (e-cvt lop) rop)
+                       else ; if we are dealing with hunks, we must save
+                            ; r0 since that contains the value we want to
+                            ; return.
+                            (if (eq type 'hunk) then (d-move 'reg 'stack)
+                                                     (Push g-locs nil)
+                                                     (incr g-loccnt))
+                            (e-write3 'moval rop '#.Cstack)
+                            (let ((g-loc "*(sp)+") g-cc)
+                                 (d-exp arg3))
+                            (if (eq type 'hunk) then (d-move 'unstack 'reg)
+                                                     (unpush g-locs)
+                                                     (decr g-loccnt))
+                            (d-clearreg 'r0)))))
+
+#+for-68k
+(defun d-superrplacx (type)
+   (let ((arg1 (cadr v-form))
+        (arg2 (caddr v-form))
+        (arg3 (cadddr v-form))
+        lop rop semisimple)
+       (makecomment `(starting d-superrplacx ,type :: v-form = ,v-form))
+       ;
+       ; calulate index and put it in '#.fixnum-reg if it is not an immediate
+       ; set lop to the location of the index
+       (if (fixp arg1) then (setq lop `(immed ,arg1))
+          else (d-fixnumexp arg1)
+               (d-regused '#.fixnum-reg)
+               (setq lop '#.fixnum-reg))
+       ;
+       ; set rop to the location of the hunk.  If we have to
+       ; calculate the hunk, we may have to save '#.fixnum-reg.
+       ; If we are doing a rplacx (type equals hunk) then we must
+       ; return the hunk in d0.
+       (if (or (eq type 'hunk) (not (setq rop (d-simple arg2))))
+          then (if (and (eq lop '#.fixnum-reg)
+                        (not (setq semisimple (d-semisimple arg2))))
+                   then (d-move lop '#.Cstack))
+               (let ((g-loc 'a0) g-cc)
+                   (d-exp arg2))
+               (setq rop 'a0)
+               (if (and (eq lop '#.fixnum-reg) (not semisimple))
+                   then (d-move '#.unCstack lop)))
+       ;
+       ; now that the index and data block locations are known, we
+       ; caclulate the location of the index'th element of hunk
+       (setq rop
+            (d-structgen lop rop
+                         (if (eq type 'flonum-block) then 8 else 4)))
+       ;
+       ; the code to calculate the value to store and the actual
+       ; storing depends on the type of data block we are storing in.
+       (if (eq type 'flonum-block) 
+          then (break "flonum stuff not in yet")
+               (if (setq lop (d-simple `(cdr ,arg3)))
+                   then (e-write3 'movq (e-cvt lop) rop)
+                   else ; preserve rop since it may be destroyed
+                        ; when arg3 is calculated
+                        (e-write3 'movaq rop '#.Cstack)
+                        (let ((g-loc 'd0) g-cc)
+                            (d-exp arg3))
+                        (d-clearreg 'd0)
+                        (e-write3 'movq '(0 d0) "*(sp)+"))
+       elseif (and (eq type 'fixnum-block)
+                   (setq arg3 `(cdr ,arg3))
+                   nil)
+            ; fixnum-block is like hunk except we must grab the
+            ; fixnum value out of its box, hence the (cdr arg3)
+          thenret
+          else (if (setq lop (d-simple arg3))
+                   then (e-move (e-cvt lop) rop)
+                   else ; if we are dealing with hunks, we must save
+                        ; d0 since that contains the value we want to
+                        ; return.
+                        (if (eq type 'hunk)
+                            then (L-push 'a0)
+                                 (push nil g-locs)
+                                 (incr g-loccnt))
+                        (e-write3 'lea rop 'a5)
+                        (C-push 'a5)
+                        (let ((g-loc '(racc * 0 sp)) g-cc)
+                            (d-exp arg3))
+                        (if (eq type 'hunk)
+                            then (L-pop 'd0)
+                                 (unpush g-locs)
+                                 (decr g-loccnt))))
+       (makecomment '(d-superrplacx done))))
+                           
+;--- cc-cxxr :: compile a "c*r" instr where *
+;              is any sequence of a's and d's
+;      - arg : argument of the cxxr function
+;      - pat : a list of a's and d's in the reverse order of that
+;                      which appeared between the c and r
+;
+#+for-vax
+(defun cc-cxxr (arg pat)
+  (prog (resloc loc qloc sofar togo keeptrack)
+       ; check for the special case of nil, since car's and cdr's
+       ; are nil anyway
+       (if (null arg)
+           then (if g-loc then (d-move 'Nil g-loc)
+                    (d-handlecc)
+                 elseif (cdr g-cc) then (e-goto (cdr g-cc)))
+                (return))
+                                     
+       (if (and (symbolp arg) (setq qloc (d-bestreg arg pat)))
+           then (setq resloc (car qloc)
+                      loc   resloc
+                      sofar  (cadr qloc)
+                      togo   (caddr qloc))
+           else (setq resloc
+                      (if (d-simple arg)
+                          thenret
+                          else (let ((g-loc 'reg)
+                                     (g-cc nil)
+                                     (g-ret nil))
+                                   (d-exp arg))
+                               'r0))
+              (setq sofar nil togo pat))
+
+       (if (and arg (symbolp arg)) then (setq keeptrack t))
+
+       ; if resloc is a global variable, we must move it into a register
+       ; right away to be able to do car's and cdr's
+       (if (and (dtpr resloc) (or (eq (car resloc) 'bind)
+                                 (eq (car resloc) 'vstack)))
+          then (d-move resloc 'reg)
+               (setq resloc 'r0))
+
+       ; now do car's and cdr's .  Values are placed in r0. We stop when
+       ; we can get the result in one machine instruction.  At that point
+       ; we see whether we want the value or just want to set the cc's.
+       ; If the intermediate value is in a register, 
+       ; we can do : car cdr cddr cdar
+       ; If the intermediate value is on the local vrbl stack or lbind
+       ; we can do : cdr
+       (do ((curp togo newp)
+           (newp))
+          ((null curp) (if g-loc then (d-movespec loc g-loc)
+                           elseif g-cc then (e-tst loc))
+                       (d-handlecc))
+          (if (symbolp resloc)
+              then (if (eq 'd (car curp))
+                       then (if (or (null (cdr curp))
+                                    (eq 'a (cadr curp)))
+                                then (setq newp (cdr curp)   ; cdr
+                                           loc `(0 ,resloc)
+                                           sofar (append sofar (list 'd)))
+                                else (setq newp (cddr curp)  ; cddr
+                                           loc `(* 0 ,resloc)
+                                           sofar (append sofar
+                                                         (list 'd 'd))))
+                       else (if (or (null (cdr curp))
+                                    (eq 'a (cadr curp)))
+                                then (setq newp (cdr curp)   ; car
+                                           loc `(4 ,resloc)
+                                           sofar (append sofar (list 'a)))
+                                else (setq newp (cddr curp)  ; cdar
+                                           loc `(* 4 ,resloc)
+                                           sofar (append sofar
+                                                         (list 'a 'd)))))
+              elseif (and (eq 'd (car curp))
+                          (not (eq '* (car (setq loc (e-cvt resloc))))))
+                then (setq newp (cdr curp)     ; (cdr <local>)
+                           loc (cons '* loc)
+                           sofar (append sofar (list 'd)))
+              else  (setq loc (e-cvt resloc)
+                          newp curp))
+          (if newp                     ; if this is not the last move
+              then (setq resloc
+                         (d-allocreg (if keeptrack then nil else 'r0)))
+                   (d-movespec loc resloc)
+                   (if keeptrack then (d-inreg resloc (cons arg sofar)))))))
+
+#+for-68k
+(defun cc-cxxr (arg pat)
+   (prog (resloc loc qloc sofar togo keeptrack)
+       (makecomment '(starting cc-cxxr))
+       ; check for the special case of nil, since car's and cdr's
+       ; are nil anyway
+       (if (null arg)
+          then (if g-loc then (d-move 'Nil g-loc))
+               (if (cdr g-cc) then (e-goto (cdr g-cc)))
+               (return))
+       (if (and (symbolp arg) (setq qloc (d-bestreg arg pat)))
+          then (setq resloc (car qloc)
+                     loc   resloc
+                     sofar  (cadr qloc)
+                     togo   (caddr qloc))
+          else (setq resloc
+                     (if (d-simple arg) thenret
+                         else (d-clearreg 'a0)
+                              (let ((g-loc 'areg)
+                                    (g-cc nil)
+                                    (g-ret nil))
+                                  (d-exp arg))
+                              'a0))
+               (setq sofar nil togo  pat))
+       (if (and arg (symbolp arg)) then (setq keeptrack t))
+       ;
+       ; if resloc is a global variable, we must move it into a register
+       ; right away to be able to do car's and cdr's
+       (if (and (dtpr resloc) (or (eq (car resloc) 'bind)
+                                 (eq (car resloc) 'vstack)))
+          then (d-move resloc 'areg)
+               (setq resloc 'a0))
+       ; now do car's and cdr's .  Values are placed in a0. We stop when
+       ; we can get the result in one machine instruction.  At that point
+       ; we see whether we want the value or just want to set the cc's.
+       ; If the intermediate value is in a register,
+       ; we can do : car cdr cddr cdar
+       ; If the intermediate value is on the local vrbl stack or lbind
+       ; we can do : cdr
+       (do ((curp togo newp)
+           (newp))
+          ((null curp)
+           (if g-loc then (d-movespec loc g-loc))
+           ;
+           ;;;important: the below kludge is needed!!
+           ;;;consider the compilation of the following:
+           ;
+           ;;; (cond ((setq c (cdr c)) ...))
+           ;;; the following instructions are generated:
+           ;;; movl  a4@(N),a5    ; the setq
+           ;;; movl  a5@,a4@(N)
+           ;;; movl  a4@,a5       ; the last two are generated if g-cc
+           ;;; cmpl  a5@,d7       ; is non-nil
+           ;
+           ;;; observe that the original value the is supposed to set
+           ;;; the cc's is clobered in the operation!!
+           ;(msg "g-loc: " (e-cvt g-loc) N "loc: " loc N)
+           (if g-cc
+               then (if (and (eq '* (car loc))
+                             (equal (caddr loc) (cadr (e-cvt g-loc))))
+                        then (e-cmpnil '(0 a5))
+                        else (e-cmpnil loc)))
+           (d-handlecc))
+          (if (symbolp resloc)
+              then (if (eq 'd (car curp))
+                       then (if (or (null (cdr curp))
+                                    (eq 'a (cadr curp)))
+                                then (setq newp (cdr curp)   ; cdr
+                                           loc `(0 ,resloc)
+                                           sofar (append sofar (list 'd)))
+                                else (setq newp (cddr curp)  ; cddr
+                                           loc `(* 0 ,resloc)
+                                           sofar (append sofar
+                                                         (list 'd 'd))))
+                       else (if (or (null (cdr curp))
+                                    (eq 'a (cadr curp)))
+                                then (setq newp (cdr curp)   ; car
+                                           loc `(4 ,resloc)
+                                           sofar (append sofar (list 'a)))
+                                else (setq newp (cddr curp)  ; cdar
+                                           loc `(* 4 ,resloc)
+                                           sofar (append sofar
+                                                         (list 'a 'd)))))
+           elseif (and (eq 'd (car curp))
+                       (not (eq '* (car (setq loc (e-cvt resloc))))))
+              then (setq newp (cdr curp)       ; (cdr <local>)
+                         loc (cons '* loc)
+                         sofar (append sofar (list 'd)))
+              else  (setq loc (e-cvt resloc)
+                          newp curp))
+          (if newp                     ; if this is not the last move
+              then (setq resloc
+                         (d-alloc-register 'a
+                                           (if keeptrack then nil else 'a1)))
+                   (d-movespec loc resloc)
+                   ;(if keeptrack then (d-inreg resloc (cons arg sofar)))
+                   ))
+       (makecomment '(done with cc-cxxr))))
diff --git a/usr/src/ucb/lisp/liszt/funb.l b/usr/src/ucb/lisp/liszt/funb.l
new file mode 100644 (file)
index 0000000..7c7374f
--- /dev/null
@@ -0,0 +1,785 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file funb
+   "$Header: funb.l,v 1.12 83/08/28 17:14:58 layer Exp $")
+
+;;; ----       f u n b                         function compilation
+;;;
+;;;                            -[Wed Aug 24 17:14:56 1983 by layer]-
+
+;--- c-declare :: handle the "declare" form
+; if a declare is seen inside a function definition, we just 
+; ignore it.  We probably should see what it is declareing, as it
+; might be declaring a special.
+;
+(defun c-declare nil nil)
+
+;--- c-do :: compile a "do" expression
+;
+; a do has this form:
+;  (do vrbls tst . body)
+; we note the special case of tst being nil, in which case the loop
+; is evaluated only once, and thus acts like a let with labels allowed.
+; The do statement is a cross between a prog and a lambda. It is like
+; a prog in that labels are allowed. It is like a lambda in that
+; we stack the values of all init forms then bind to the variables, just
+; like a lambda expression (that is the initial values of even specials
+; are stored on the stack, and then copied into the value cell of the
+; atom during the binding phase. From then on the stack location is
+; not used).
+;
+(defun c-do nil
+   (let (b-vrbls b-tst b-body chklab bodylab x-repeat x-vrbs x-fst
+                g-loc g-cc oldreguse (g-decls g-decls))
+       (forcecomment '(beginning do))
+       (setq g-loc 'reg  chklab (d-genlab)   bodylab (d-genlab))
+
+       (if (and (cadr v-form) (atom (cadr v-form)))
+          then (setq v-form (d-olddo-to-newdo (cdr v-form))))
+
+       (push (cons 'do 0) g-locs)              ; begin our frame
+
+       (setq b-vrbls (cadr v-form)
+            b-tst   (caddr v-form)
+            b-body  (cdddr v-form))
+
+       (d-scanfordecls b-body)
+
+       ; push value of init forms on stack
+       (d-pushargs (mapcar '(lambda (x)
+                               (if (atom x)
+                                   then nil ; no init form => nil
+                                   else (cadr x)))
+                          b-vrbls))
+
+       ; now bind to  the variables in the vrbls form
+       (d-bindlamb (mapcar '(lambda (x)
+                               (if (atom x) then x
+                                   else (car x)))
+                          b-vrbls))
+
+       ; search through body for all labels and assign them gensymed labels
+       (push (cons (d-genlab)
+                  (do ((ll b-body (cdr ll))
+                       (res))
+                      ((null ll) res)
+                      (if (and (car ll) (symbolp (car ll)))
+                          then (Push res
+                                     (cons (car ll) (d-genlab))))))
+            g-labs)
+
+       ; if the test is non nil, we do the test
+       ; another strange thing, a test form of (pred) will not return
+       ; the value of pred if it is not nil! it will return nil -- in this
+       ; way, it is not like a cond clause
+       (d-clearreg)
+       (if b-tst then (e-label chklab)
+          (let ((g-cc (cons nil bodylab)) g-loc g-ret)
+              (d-exp (car b-tst)))     ; eval test
+          ; if false, do body
+          (if (cdr b-tst) 
+              then (setq oldreguse (copy g-reguse))
+                   (d-exps (cdr b-tst))
+                   (setq g-reguse oldreguse)
+              else  (d-move 'Nil 'reg))
+          (e-goto (caar g-labs))               ; leave do
+          (e-label bodylab))           ; begin body
+
+       ; process body
+       (do ((ll b-body (cdr ll))
+           (g-cc) (g-loc)(g-ret))
+          ((null ll))
+          (if (or (null (car ll)) (not (symbolp (car ll))))
+              then (d-exp (car ll))
+              else (e-label (cdr (assoc (car ll) (cdar g-labs))))
+                   (d-clearreg)))
+
+       (if b-tst
+          then ; determine all repeat forms which must be
+               ; evaluated, and all the variables affected.
+               ; store the results in x-repeat and  x-vrbs
+               ; if there is just one repeat form, we calculate
+               ; its value directly into where it is stored,
+               ; if there is more than one, we stack them
+               ; and then store them back at once.
+               (do ((ll b-vrbls (cdr ll)))
+                   ((null ll))
+                   (if (and (dtpr (car ll)) (cddar ll))
+                       then (Push x-repeat (caddar ll))
+                            (Push x-vrbs   (caar ll))))
+               (if x-vrbs 
+                   then (if (null (cdr x-vrbs))  ; if just one repeat
+                            then (let ((g-loc (d-locv (car x-vrbs)))
+                                       (g-cc nil))
+                                     (d-exp (car x-repeat)))
+                            else (setq x-fst (car x-repeat))
+                                 (d-pushargs (nreverse
+                                                 (cdr x-repeat)))
+                                 (let ((g-loc (d-locv (car x-vrbs)))
+                                       (g-cc)
+                                       (g-ret))
+                                     (d-exp x-fst))
+                                 (do ((ll (cdr x-vrbs) (cdr ll)))
+                                     ((null ll))
+                                     (d-move 'unstack
+                                             (d-locv (car ll)))
+                                     (setq g-locs (cdr g-locs))
+                                     (decr g-loccnt))))
+               (e-goto chklab))
+
+       (e-label (caar g-labs))                 ; end of do label
+       (d-clearreg)
+       (d-unbind)
+       (setq g-labs (cdr g-labs))))
+
+;--- d-olddo-to-newdo  :: map old do to new do
+;
+; form of old do is  (do var tst . body)
+; where var is a symbol, not nil
+;
+(defun d-olddo-to-newdo (v-l)
+  `(do ((,(car v-l) ,(cadr v-l) ,(caddr v-l)))
+       (,(cadddr v-l))
+       ,@(cddddr v-l)))
+
+;--- cc-dtpr :: check for dtprness
+;
+(defun cc-dtpr nil
+  (d-typesimp (cadr v-form) #.(immed-const 3)))
+
+;--- cc-eq :: compile an "eq" expression
+;
+(defun cc-eq nil
+   (let ((arg1 (cadr v-form))
+        (arg2 (caddr v-form))
+        arg1loc
+        arg2loc)
+       (if (setq arg2loc (d-simple arg2))
+          then (if (setq arg1loc (d-simple arg1))
+                   then ; eq <simple> <simple>
+                        (d-cmp arg1loc arg2loc)
+                   else ; eq <nonsimple> <simple>
+                        (let ((g-loc 'reg)     ; put <nonsimple> in reg
+                              ; must rebind because
+                              ; cc->& may have modified
+                              (g-trueop #+for-vax 'jneq #+for-68k 'jne)
+                              (g-falseop #+for-vax 'jeql #+for-68k 'jeq)
+                              g-cc
+                              g-ret)
+                            (d-exp arg1))
+                        (d-cmp 'reg arg2loc))
+          else ; since second is nonsimple, must stack first
+               ; arg out of harms way
+               (let ((g-loc 'stack)
+                     (g-trueop #+for-vax 'jneq #+for-68k 'jne)
+                     (g-falseop #+for-vax 'jeql #+for-68k 'jeq)
+                     g-cc
+                     g-ret)
+                   (d-exp arg1)
+                   (push nil g-locs)
+                   (incr g-loccnt)
+                   (setq g-loc 'reg)           ; second arg to reg
+                   (d-exp arg2))
+               (d-cmp 'unstack 'reg)
+               (setq g-locs (cdr g-locs))
+               (decr g-loccnt)))
+   (d-invert))
+
+;--- cc-equal :: compile `equal'
+;
+(defun cc-equal nil
+  (let ((lab1 (d-genlab))
+       (lab11 (d-genlab))
+       lab2)
+       (d-pushargs (cdr v-form))
+       (e-cmp '(-8 #.np-reg) '(-4 #.np-reg))
+       (e-gotonil lab1)
+       (d-calltran 'equal '2)           ; not eq, try equal.
+       (d-clearreg)
+       #+for-vax (e-tst (e-cvt 'reg))
+       #+for-68k (e-cmpnil (e-cvt 'reg))
+       (e-gotot lab11)         
+       (if g-loc then (d-move 'Nil g-loc))
+       (if (cdr g-cc) then (e-goto (cdr g-cc))
+          else (e-goto (setq lab2 (d-genlab))))
+       (e-writel lab1)
+       (e-dropnp 2)
+       (e-writel lab11)
+       (if g-loc then (d-move 'T g-loc))
+       (if (car g-cc) then (e-goto (car g-cc)))
+       (if lab2 then (e-writel lab2))
+       (setq g-locs (cddr g-locs))
+       (setq g-loccnt (- g-loccnt 2))))
+
+;--- c-errset :: compile an errset expression
+;
+; the errset has this form: (errset 'value ['tag])
+; where tag defaults to t.
+;
+(defun c-errset nil
+  (let ((g-loc 'reg)
+       (g-cc nil)
+       (g-ret nil)
+       (finlab (d-genlab))
+       (beglab (d-genlab)))
+       (d-exp (if (cddr v-form) then (caddr v-form) else t))
+       (d-pushframe #.F_CATCH (d-loclit 'ER%all nil) 'reg)
+       (push nil g-labs)               ; disallow labels
+       ; If retval is non zero then an error has throw us here so we 
+       ; must recover the value thrown (from _lispretval) and leave
+       ; If retval is zero then we shoud calculate the expression 
+       ; into r0  and put a cons cell around it
+       (e-tst '_retval)
+       (e-write2 #+for-vax 'jeql #+for-68k 'jeq beglab)
+       (e-move '_lispretval (e-cvt 'reg))
+       (e-write2 #+for-vax 'jbr #+for-68k 'jra finlab)
+       (e-label beglab)
+       (let ((g-loc 'stack)
+            (g-cc nil))
+           (d-exp (cadr v-form)))
+       (d-move 'Nil 'stack)    ; haven't updated g-loc, g-loccnt but it
+                               ; shouldn't hurt (famous last words)
+       (e-quick-call '_qcons)
+       (e-label finlab)
+       (d-popframe)
+       (unpush g-locs)         ; remove (catcherrset . 0)
+       (unpush g-labs)         ; remove nil
+       (d-clearreg)))
+
+;--- cm-fixnum-cxr :: open code a fixnum-cxr expression.
+; 
+; fixnum-cxr is a compile only hacky function which accesses an element
+; of a fixnum space and boxes the resulting fixnum.  It can be used
+; for rapid access to user defined structures.
+;
+(defun cm-fixnum-cxr ()
+  `(internal-fixnum-box (cxr ,@(cdr v-form))))
+
+(defun c-internal-fixnum-box ()
+  (let ((g-cc nil)
+       (g-ret nil)
+       (g-loc '#.fixnum-reg))
+       #+for-68k (d-regused '#.fixnum-reg)
+       (d-exp (cadr v-form))
+       (e-call-qnewint)))
+
+;--- cc-offset-cxr
+; return a pointer to the address of the object instead of the object.
+;
+(defun cc-offset-cxr nil
+  (d-supercxr nil t))
+
+;--- cc-fixp :: check for a fixnum or bignum
+;
+(defun cc-fixp nil
+  (d-typecmplx (cadr v-form) 
+              '#.(immed-const (plus 1_2 1_9))))
+
+;--- cc-floatp :: check for a flonum
+;
+(defun cc-floatp nil
+  (d-typesimp (cadr v-form) #.(immed-const 4)))
+
+;--- c-funcall :: compile a funcall
+;
+; we open code a funcall the resulting object is a compiled lambda.
+; We don't open code nlambda and macro funcalls since they are
+; rarely used and it would waste space to check for them
+(defun c-funcall nil
+   (if (null (cdr v-form))
+      then (comp-err "funcall requires at least one argument " v-form))
+   (let ((g-locs g-locs)
+        (g-loccnt g-loccnt)
+        (args (length (cdr v-form)))
+        (g-loc nil)
+        (g-ret nil)
+        (g-cc nil))
+      (d-pushargs (cdr v-form))
+      (rplaca (nthcdr (1- args) g-locs) 'funcallfcn)
+
+      (d-exp '(cond ((and (symbolp funcallfcn)
+                         (getd funcallfcn))
+                    (setq funcallfcn (getd funcallfcn)))))
+            
+      (d-exp `(cond ((and (bcdp funcallfcn) (eq 'lambda (getdisc funcallfcn)))
+                       (Internal-bcdcall ,args t))
+                      (t (Internal-bcdcall  ,args nil))))))
+
+;--- c-Internal-bcdcall
+; this is a compiler internal function call.  when this occurs, there
+;  are argnum objects stacked, the first of which is a function name
+;  or bcd object.  If dobcdcall is t then we want to do a bcdcall of
+;  the first object stacked.  If it is not true then we want to
+;  call the interpreter funcall function to handle it.
+;
+(defun c-Internal-bcdcall nil
+   (let ((argnum (cadr v-form))
+        (dobcdcall (caddr v-form)))
+      (cond (dobcdcall (d-bcdcall argnum))
+           (t (d-calltran 'funcall argnum)))))
+
+;--- cc-function :: compile a function function
+;
+; function is an nlambda, which the interpreter treats as 'quote'
+; If the argument is a lambda expression, then Liszt will generate
+; a new function and generate code to return the name of
+; that function.  If the argument is a symbol, then 'symbol
+; is compiled.   It would probably be better to return the function
+; cell of the symbol, but Maclisp returns the symbol and it
+; would cause compatibility problems.
+;
+(defun cc-function nil
+   (if (or (null (cdr v-form))
+          (cddr v-form))
+      then (comp-err "Wrong number of arguments to 'function': " v-form))
+   (let ((arg (cadr v-form)))
+      (if (symbolp arg)
+        then (d-exp `',arg)
+       elseif (and (dtpr arg)
+                  (memq (car arg) '(lambda nlambda lexpr)))
+        then (let ((newname (concat "in-line-lambda:"
+                                    (setq in-line-lambda-number
+                                          (add1 in-line-lambda-number)))))
+                (Push liszt-process-forms
+                      `(def ,newname ,arg))
+                (d-exp `',newname))
+        else (comp-err "Illegal argument to 'function': " v-form))))
+
+;--- c-get :: do a get from the prop list
+;
+(defun c-get nil
+  (if (not (eq 2 (length (cdr v-form))))
+      then (comp-err "Wrong number of args to get " v-form))
+  (d-pushargs (cdr v-form))            ; there better be 2 args
+  (e-quick-call '_qget)
+  (d-clearreg)
+  (setq g-locs (cddr g-locs))
+  (setq g-loccnt (- g-loccnt 2)))
+
+;--- cm-getaccess :: compile a getaccess instruction
+;
+(defun cm-getaccess nil `(cdr ,(cadr v-form)))
+
+;--- cm-getaux :: compile a getaux instruction
+;
+(defun cm-getaux  nil `(car ,(cadr v-form)))
+
+;--- cm-getd :: compile a getd instruction
+;
+; the getd function is open coded to look in the third part of a symbol
+; cell
+;
+(defun cm-getd nil `(cxr 2 ,(cadr v-form)))
+
+;--- cm-getdata :: compile a getdata instruction
+;
+; the getdata function is open coded to look in the third part of an 
+; array header.
+(defun cm-getdata nil `(cxr 2 ,(cadr v-form)))
+
+;--- cm-getdisc  :: compile a getdisc expression
+; getdisc accessed the discipline field of a binary object.
+;
+(defun cm-getdisc nil `(cxr 1 ,(cadr v-form)))
+
+;--- c-go :: compile a "go" expression
+;
+; we only compile the (go symbol)type expression, we do not
+; allow symbol to be anything by a non null symbol.
+;
+(defun c-go nil
+   ; find number of frames we have to go down to get to the label
+   (do ((labs g-labs (cdr labs))
+       (locs g-locs)
+       (locals 0)
+       (specials 0)
+       (catcherrset 0)
+       (label))
+       ((null labs)
+       (comp-err "go label not found for expression: " (or v-form)))
+
+       (if (car labs)          ; if we have a set of labels to look at...
+          then (if (setq label
+                         (do ((lbs (cdar labs) (cdr lbs)))
+                             ((null lbs))
+                             (if (eq (caar lbs) (cadr v-form))
+                                 then (return (cdar lbs)))))
+                   then (if (not (eq labs g-labs))
+                            then (comp-note g-fname ": non local go used : "
+                                            (or v-form)))
+                        ; three stack to pop: namestack, bindstack
+                        ;   and execution stack
+                        (e-pop locals)
+                        (if (greaterp specials 0)
+                            then (e-unshallowbind specials))
+                        (if (greaterp catcherrset 0)
+                            then (comp-note g-fname
+                                            ": Go through a catch or errset "
+                                            v-form)
+                                 (do ((i 0 (1+ i)))
+                                     ((=& catcherrset i))
+                                     (d-popframe)))
+                        (e-goto label)
+                        (return)))
+       ; tally all locals, specials and catcherrsets used in this frame
+       (do ()
+          ((dtpr (car locs))
+           (if (eq 'catcherrset (caar locs))
+              then (incr catcherrset)
+            elseif (eq 'progv (caar locs))
+              then (comp-err "Attempt to 'go' through a progv"))
+           (setq specials (+ specials (cdar locs))
+                 locs (cdr locs)))
+          (setq locs (cdr locs))
+          (incr locals))))
+                       
+;--- cc-ignore :: just ignore this code
+;
+(defun cc-ignore nil
+  nil)
+
+;--- c-lambexp :: compile a lambda expression
+;
+(defun c-lambexp nil
+  (let ((g-loc (if (or g-loc g-cc) then 'reg))
+       (g-cc nil)
+       (g-locs (cons (cons 'lambda 0) g-locs))
+       (g-labs (cons nil g-labs)))
+       (d-pushargs (cdr v-form))               ; then push vals
+       (d-lambbody (car v-form))
+       (d-clearreg)))
+
+;--- d-lambbody :: do a lambda body
+;      - body : body of lambda expression, eg (lambda () dld)
+;
+(defun d-lambbody (body)
+   (let ((g-decls g-decls))
+      (d-scanfordecls (cddr body))             ; look for declarations
+      (d-bindlamb (cadr body))         ; bind locals
+      (d-clearreg)
+      (d-exp (do ((ll (cddr body) (cdr ll))
+                 (g-loc)
+                 (g-cc)
+                 (g-ret))
+                ((null (cdr ll)) (car ll))
+                (d-exp (car ll))))
+
+      (d-unbind)))                             ; unbind this frame
+
+;--- d-bindlamb :: bind  variables in lambda list
+;      - vrbs : list of lambda variables, may include nil meaning ignore
+;
+(defun d-bindlamb (vrbs)
+  (let ((res (d-bindlrec (reverse vrbs) g-locs 0 g-loccnt)))
+       (if res then (e-setupbind)
+                   (mapc '(lambda (vrb) (e-shallowbind (car vrb) (cdr vrb)))
+                         res)
+                   (e-unsetupbind))))
+  
+;--- d-bindlrec :: recusive routine to bind lambda variables
+;      - vrb : list of variables yet to bind
+;      - locs : current location in g-loc
+;      - specs : number of specials seen so far
+;      - lev  : how far up from the bottom of stack we are.
+; returns: list of elements, one for each special, of this form:
+;              (<specialvrbname> stack <n>)
+;      where specialvrbname is the name of the special variable, and n is
+;      the distance from the top of the stack where its initial value is 
+;      located
+; also: puts the names of the local variables in the g-locs list, as well
+;      as placing the number of special variables in the lambda header.
+;
+(defun d-bindlrec (vrb locs specs lev)
+   (if vrb 
+       then (let ((spcflg (d-specialp (car vrb)))
+                 retv)
+               (if spcflg then (setq specs (1+ specs)))
+
+               (if (cdr vrb)           ; if more vrbls to go ...
+                   then (setq retv (d-bindlrec (cdr vrb)
+                                               (cdr locs)
+                                               specs
+                                               (1- lev)))
+                   else (rplacd (cadr locs)
+                                specs))        ; else fix up lambda hdr
+
+               (if (not spcflg) then (rplaca locs (car vrb))
+                   else (Push retv `(,(car vrb) stack ,lev)))
+
+               retv)))
+
+;--- d-scanfordecls
+; forms - the body of a lambda, prog or do.
+;  we look down the form for 'declare' forms.  They should be at the
+;  beginning, but there are macros which may unintentionally put forms
+;  in front of user written forms.  Thus we check a little further than
+;  the first form.
+(defun d-scanfordecls (forms)
+   ; look for declarations in the first few forms
+   (do ((count 3 (1- count)))
+       ((= 0 count))
+       (cond ((and (dtpr (car forms))
+                  (eq 'declare (caar forms))
+                  (apply 'liszt-declare (cdar forms)))))
+       (setq forms (cdr forms))))
+
+;--- c-list :: compile a list expression
+;
+; this is compiled as a bunch of conses with a nil pushed on the
+; top for good measure
+;
+(defun c-list nil
+  (prog (nargs)
+       (setq nargs (length (cdr v-form)))
+       (makecomment '(list expression))
+       (if (zerop nargs)
+           then (d-move 'Nil 'reg)     ; (list) ==> nil
+                (return))
+       (d-pushargs (cdr v-form))
+       #+for-vax (e-write2 'clrl '#.np-plus)   ; stack one nil
+       #+for-68k (L-push (e-cvt 'Nil))
+
+       ; now do the consing
+       (do ((i (max 1 nargs) (1- i)))
+          ((zerop i))
+          (e-quick-call '_qcons)
+          (d-clearreg)
+          (if (> i 1) then (L-push (e-cvt 'reg))))
+
+       (setq g-locs (nthcdr nargs g-locs)
+            g-loccnt (- g-loccnt nargs))))
+
+;--- d-mapconvert - access : function to access parts of lists
+;                - join         : function to join results
+;                - resu         : function to apply to result
+;                - form         : mapping form
+;      This function converts maps to an equivalent do form.
+;
+;  in this function, the variable vrbls contains a list of forms, one form
+;  per list we are mapping over.  The form of the form is 
+;    (dummyvariable  realarg  (cdr dummyvariable))
+; realarg may be surrounded by (setq <variable which holds result> realarg)
+; in the case that the result is the list to be mapped over (this only occurs
+; with the function mapc).
+;
+(defun d-mapconvert (access join resu form )
+   (prog (vrbls finvar acc accform compform
+               tmp testform tempvar lastvar)
+
+       (setq finvar (gensym 'X)   ; holds result
+
+            vrbls
+            (reverse
+                (maplist '(lambda (arg)
+                              ((lambda (temp)
+                                   (cond ((or resu (cdr arg))
+                                          `(,temp ,(car arg)
+                                             (cdr ,temp)))
+                                         (t `(,temp
+                                               (setq ,finvar
+                                                      ,(car arg))
+                                               (cdr ,temp)))))
+                               (gensym 'X)))
+                         (reverse (cdr form))))
+
+            ; the access form will either be nil or car.  If it is
+            ; nil, then we are doing something like a maplist,
+            ; if the access form is car, then we are doing something
+            ; like a mapcar.
+            acc (mapcar '(lambda (tem)
+                             (cond (access `(,access ,(car tem)))
+                                   (t (car tem))))
+                        vrbls)
+
+            accform (cond ((or (atom (setq tmp (car form)))
+                               (null (setq tmp (d-macroexpand tmp)))
+                               (not (member (car tmp) '(quote function))))
+                           `(funcall ,tmp ,@acc))
+                          (t `(,(cadr tmp) ,@acc)))
+
+            ; the testform checks if any of the lists we are mapping
+            ; over is nil, in which case we quit.
+            testform (cond ((null (cdr vrbls)) `(null ,(caar vrbls)))
+                           (t `(or ,@(mapcar '(lambda (x)
+                                                  `(null ,(car  x)))
+                                             vrbls)))))
+
+       ; in the case of mapcans and mapcons, you need two
+       ; extra variables to simulate the nconc.
+       ; testvar gets intermediate results and lastvar
+       ; points to then end of the list
+       (if (eq join 'nconc)
+          then (setq tempvar (gensym 'X)
+                     lastvar (gensym 'X)
+                     vrbls `((,tempvar) (,lastvar) ,@vrbls)))
+
+       (return
+          `((lambda
+                (,finvar)
+                (liszt-internal-do
+                    ( ,@vrbls)
+                    (,testform)
+                    ,(cond ((eq join 'nconc)
+                            `(cond ((setq ,tempvar ,accform)
+                                    (cond (,lastvar
+                                            (liszt-internal-do
+                                                ()
+                                                ((null (cdr ,lastvar)))
+                                                (setq ,lastvar
+                                                      (cdr ,lastvar)))
+                                            (rplacd ,lastvar ,tempvar))
+                                          (t (setq ,finvar
+                                                    (setq ,lastvar
+                                                          ,tempvar)))))))
+                           (join `(setq ,finvar (,join ,accform ,finvar)))
+                           (t accform)))
+                ,(cond ((eq resu 'identity) finvar)
+                       (resu `(,resu ,finvar))
+                       (t finvar)))
+            nil ))))
+
+; apply to successive elements, return second arg
+(defun cm-mapc nil
+         (d-mapconvert 'car nil nil (cdr v-form)))
+
+; apply to successive elements, return list of results
+(defun cm-mapcar nil
+         (d-mapconvert 'car 'cons 'nreverse (cdr v-form)))
+
+; apply to successive elements, returned nconc of results
+(defun cm-mapcan nil
+         (d-mapconvert 'car 'nconc 'identity (cdr v-form)))
+
+; apply to successive sublists, return second arg
+(defun cm-map nil
+         (d-mapconvert nil nil nil (cdr v-form)))
+
+; apply to successive sublists, return list of results
+(defun cm-maplist nil
+         (d-mapconvert nil 'cons 'reverse (cdr v-form)))
+
+; apply to successive sublists, return nconc of results
+(defun cm-mapcon nil
+         (d-mapconvert nil 'nconc 'identity (cdr v-form)))
+
+;--- cc-memq :: compile a memq expression
+;
+#+for-vax
+(defun cc-memq nil
+  (let ((loc1 (d-simple (cadr v-form)))
+       (loc2 (d-simple (caddr v-form)))
+       looploc finlab)
+       (if loc2
+          then (d-clearreg 'r1)
+               (if loc1
+                   then (d-move loc1 'r1)
+                   else (let ((g-loc 'r1)
+                              g-cc
+                              g-ret)
+                            (d-exp (cadr v-form))))
+               (d-move loc2 'reg)
+          else (let ((g-loc 'stack)
+                     g-cc
+                     g-ret)
+                   (d-exp (cadr v-form)))
+               (push nil g-locs)
+               (incr g-loccnt)
+               (let ((g-loc 'reg)
+                     g-cc
+                     g-ret)
+                   (d-exp (caddr v-form)))
+               (L-pop 'r1)
+               (d-clearreg 'r1)
+               (unpush g-locs)
+               (decr g-loccnt))
+       ; now set up the jump addresses
+       (if (null g-loc)
+          then (setq loc1 (if (car g-cc) thenret else (d-genlab))
+                     loc2 (if (cdr g-cc) thenret else (d-genlab)))
+          else (setq loc1 (d-genlab)
+                     loc2 (d-genlab)))
+
+       (setq looploc (d-genlab))
+       (e-tst 'r0)
+       (e-write2 'jeql loc2)
+       (e-label looploc)
+       (e-cmp 'r1 '(4 r0))
+       (e-write2 'jeql loc1)
+       (e-move '(0 r0) 'r0)
+       (e-write2 'jneq looploc)
+       (if g-loc
+          then (e-label loc2)          ; nil result
+               (d-move 'reg g-loc)
+               (if (cdr g-cc)
+                   then (e-goto (cdr g-cc))
+                   else (e-goto (setq finlab (d-genlab))))
+          else (if (cdr g-cc)
+                   then (e-goto (cdr g-cc))
+                   else (e-label loc2)))
+       (if g-loc
+          then (e-label loc1)          ; non nil result
+               (d-move 'reg g-loc)
+               (if (car g-cc) then (e-goto (car g-cc)))
+          else (if (null (car g-cc)) then (e-label loc1)))
+       (if finlab then (e-label finlab))))
+
+#+for-68k
+(defun cc-memq nil
+   (let ((loc1 (d-simple (cadr v-form)))
+        (loc2 (d-simple (caddr v-form)))
+        looploc finlab
+        (tmp-data-reg (d-alloc-register 'd nil)))
+       (d-clearreg tmp-data-reg)
+       (d-clearreg 'a0)
+       (if loc2
+          then (if loc1
+                   then (d-move loc1 tmp-data-reg)
+                   else (let ((g-loc tmp-data-reg)
+                              g-cc
+                              g-ret)
+                            (d-exp (cadr v-form))))
+               (d-move loc2 'reg)
+          else (let ((g-loc 'stack)
+                     g-cc
+                     g-ret)
+                   (d-exp (cadr v-form)))
+               (push nil g-locs)
+               (incr g-loccnt)
+               (let ((g-loc 'reg)
+                     g-cc
+                     g-ret)
+                   (d-exp (caddr v-form)))
+               (L-pop tmp-data-reg)
+               (unpush g-locs)
+               (decr g-loccnt))
+       ; now set up the jump addresses
+       (if (null g-loc)
+          then (setq loc1 (if (car g-cc) thenret else (d-genlab))
+                     loc2 (if (cdr g-cc) thenret else (d-genlab)))
+          else (setq loc1 (d-genlab)
+                     loc2 (d-genlab)))
+       (setq looploc (d-genlab))
+       (e-cmpnil 'd0)
+       (e-write2 'jeq loc2)
+       (e-move 'd0 'a0)
+       (e-label looploc)
+       (e-cmp tmp-data-reg '(4 a0))
+       (e-write2 'jeq loc1)
+       (e-move '(0 a0) 'a0)
+       (e-cmpnil 'a0)
+       (e-write2 'jne looploc)
+       (e-move 'a0 'd0)
+       (if g-loc
+          then (e-label loc2)                  ; nil result
+               (d-move 'reg g-loc)
+               (if (cdr g-cc)
+                   then (e-goto (cdr g-cc))
+                   else (e-goto (setq finlab (d-genlab))))
+          else (if (cdr g-cc)
+                   then (e-goto (cdr g-cc))
+                   else (e-label loc2)))
+       (if g-loc
+          then (e-label loc1)                  ; non nil result
+               (d-move 'a0 g-loc)              ;a0 was cdr of non-nil result
+               (if (car g-cc) then (e-goto (car g-cc)))
+          else (if (null (car g-cc)) then (e-label loc1)))
+       (if finlab then (e-label finlab))))
diff --git a/usr/src/ucb/lisp/liszt/func.l b/usr/src/ucb/lisp/liszt/func.l
new file mode 100644 (file)
index 0000000..caa655d
--- /dev/null
@@ -0,0 +1,579 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file func
+   "$Header: func.l,v 1.12 83/08/28 17:12:47 layer Exp $")
+
+;;; ----       f u n c                         function compilation
+;;;
+;;;                    -[Wed Aug 24 10:51:11 1983 by layer]-
+
+; cm-ncons :: macro out an ncons expression
+;
+(defun cm-ncons nil
+  `(cons ,(cadr v-form) nil))
+
+; cc-not :: compile a "not" or "null" expression
+;
+(defun cc-not nil
+  (makecomment '(beginning not))
+  (if (null g-loc)
+      then (let ((g-cc (cons (cdr g-cc) (car g-cc)))
+                (g-ret nil))
+               (d-exp (cadr v-form)))
+      else (let ((finlab (d-genlab))
+                (finlab2 (d-genlab))
+                (g-ret nil))
+               ; eval arg and jump to finlab if nil
+               (let ((g-cc (cons finlab nil))
+                     g-loc)
+                    (d-exp (cadr v-form)))
+               ; didn't jump, answer must be t
+               (d-move 'T g-loc)
+               (if (car g-cc)
+                   then (e-goto (car g-cc))
+                   else (e-goto finlab2))
+               (e-label finlab)
+               ; answer is nil
+               (d-move 'Nil g-loc)
+               (if (cdr g-cc) then (e-goto (cdr g-cc)))
+               (e-label finlab2))))
+
+;--- cc-numberp :: check for numberness
+;
+(defun cc-numberp nil
+  (d-typecmplx (cadr v-form) 
+              '#.(immed-const (plus 1_2 1_4 1_9))))
+
+;--- cc-or :: compile an "or" expression
+;
+(defun cc-or nil
+  (let ((finlab (d-genlab))
+       (finlab2)
+       (exps (if (cdr v-form) thenret else '(nil)))) ; (or) => nil
+       (if (null (car g-cc))
+          then (d-exp (do ((g-cc (cons finlab nil))
+                           (g-loc (if g-loc then 'reg))
+                           (g-ret nil)
+                           (ll exps (cdr ll)))
+                          ((null (cdr ll)) (car ll))
+                          (d-exp (car ll))))
+               (if g-loc
+                   then (setq finlab2 (d-genlab))
+                        (e-goto finlab2)
+                        (e-label finlab)
+                        (d-move 'reg g-loc)
+                        (e-label finlab2)
+                   else (e-label finlab))
+          else (if (null g-loc) then (setq finlab (car g-cc)))
+               (d-exp (do ((g-cc (cons finlab nil))
+                           (g-loc (if g-loc then 'reg))
+                           (g-ret nil)
+                           (ll exps (cdr ll)))
+                          ((null (cdr ll)) (car ll))
+                          (d-exp (car ll))))
+               (if g-loc
+                   then (setq finlab2 (d-genlab))
+                        (e-goto finlab2)
+                        (e-label finlab)
+                        (d-move 'reg g-loc)
+                        (e-goto (car g-cc))    ; result is t
+                        (e-label finlab2)))
+       (d-clearreg)))  ;we are not sure of the state due to possible branches.
+                              
+;--- c-prog :: compile a "prog" expression
+;
+; for interlisp compatibility, we allow the formal variable list to
+; contain objects of this form (vrbl init) which gives the initial value
+; for that variable (instead of nil)
+;
+(defun c-prog nil
+   (let ((g-decls g-decls))
+      (let (g-loc g-cc seeninit initf
+           (p-rettrue g-ret) (g-ret nil)
+           ((spcs locs initsv . initsn) (d-classify (cadr v-form))))
+
+        (e-pushnil (length locs))      ; locals initially nil
+        (d-bindprg spcs locs)          ; bind locs and specs
+
+        (cond (initsv (d-pushargs initsv)
+                      (mapc '(lambda (x)
+                                (d-move 'unstack (d-loc x))
+                                (decr g-loccnt)
+                                (unpush g-locs))
+                            (nreverse initsn))))
+
+        ; determine all possible labels
+        (do ((ll (cddr v-form) (cdr ll))
+             (labs nil))
+            ((null ll) (setq g-labs `((,(d-genlab) ,@labs)
+                                      ,@g-labs)))
+            (if (and (car ll) (symbolp (car ll)))
+               then (if (assq (car ll) labs)
+                       then (comp-err "label is mulitiply defined " (car ll))
+                       else (setq labs (cons (cons (car ll) (d-genlab))
+                                             labs)))))
+
+        ; compile each form which is not a label
+        (d-clearreg)           ; unknown state after binding
+        (do ((ll (cddr v-form) (cdr ll)))
+            ((null ll))
+            (if (or (null (car ll)) (not (symbolp (car ll))))
+               then (d-exp (car ll))
+               else (e-label (cdr (assq (car ll) (cdar g-labs))))
+                    (d-clearreg))))            ; dont know state after label
+
+      ; result is nil if fall out and care about value
+      (if (or g-cc g-loc) then (d-move 'Nil 'reg))
+
+      (e-label (caar g-labs))          ; return to label
+      (setq g-labs (cdr g-labs))
+      (d-unbind)))                     ; unbind our frame
+
+;--- d-bindprg :: do binding for a prog expression
+;      - spcs : list of special variables
+;      - locs : list of local variables
+;      - specinit : init values for specs (or nil if all are nil)
+;
+(defun d-bindprg (spcs locs)
+   ; place the local vrbls and prog frame entry on the stack
+   (setq g-loccnt (+ g-loccnt (length locs))
+        g-locs (nconc locs `((prog . ,(length spcs)) ,@g-locs)))
+
+   ; now bind the specials, if any, to nil
+   (if spcs then (e-setupbind)
+       (mapc '(lambda (vrb)
+                 (e-shallowbind vrb 'Nil))
+            spcs)
+       (e-unsetupbind)))
+
+;--- d-unbind :: remove one frame from g-locs
+;
+(defun d-unbind nil
+   (do ((count 0 (1+ count)))
+       ((dtpr (car g-locs))
+       (if (not (zerop (cdar g-locs)))
+           then (e-unshallowbind (cdar g-locs)))
+       (cond ((not (zerop count))
+              (e-dropnp count)
+
+              (setq g-loccnt (- g-loccnt count))))
+       (setq g-locs (cdr g-locs)))
+       (setq g-locs (cdr g-locs))))
+       
+;--- d-classify :: seperate variable list into special and non-special
+;      - lst : list of variables
+; returns ( xxx yyy zzz . aaa) 
+;              where xxx is the list of special variables and
+;              yyy is the list of local variables
+;              zzz are the non nil initial values for prog variables
+;              aaa are the names corresponding to the values in zzz
+;
+(defun d-classify (lst)
+   (do ((ll lst (cdr ll))
+       (locs) (spcs) (init) (initsv) (initsn)
+       (name))
+       ((null ll) (cons spcs (cons locs (cons initsv initsn))))
+       (if (atom (car ll))
+          then (setq name (car ll))
+          else (setq name (caar ll))
+               (push name initsn)
+               (push (cadar ll) initsv))
+       (if (d-specialp name)
+          then (push name spcs)
+          else (push name locs))))
+
+; cm-progn :: compile a "progn" expression
+;
+(defun cm-progn nil
+  `((lambda nil ,@(cdr v-form))))
+
+; cm-prog1 :: compile a "prog1" expression
+;
+(defun cm-prog1 nil
+  (let ((gl (d-genlab)))
+       `((lambda (,gl) 
+                ,@(cddr v-form)
+                ,gl)
+        ,(cadr v-form))))
+
+; cm-prog2 :: compile a "prog2" expression
+;
+(defun cm-prog2 nil
+   (let ((gl (d-genlab)))
+       `((lambda (,gl)
+            ,(cadr v-form)
+            (setq ,gl ,(caddr v-form))
+            ,@(cdddr v-form)
+            ,gl)
+        nil)))
+
+;--- cm-progv :: compile a progv form
+;  a progv form looks like (progv 'l-vars 'l-inits 'g-exp1 ... 'g-expn)
+; l-vars should be a list of variables, l-inits a list of initial forms
+; We cannot permit returns and go-s through this form.
+;
+; we stack a (progv . 0) form on g-locs so that return and go will know
+; not to try to go through this form.
+;
+(defun c-progv nil
+   (let ((gl (d-genlab))
+        (g-labs (cons nil g-labs))
+        (g-locs (cons '(progv . 0) g-locs)))
+       (d-exp `((lambda (,gl)
+                   (prog1 (progn ,@(cdddr v-form))
+                          (internal-unbind-vars ,gl)))
+               (internal-bind-vars ,(cadr v-form) ,(caddr v-form))))))
+
+(defun c-internal-bind-vars nil
+   (let ((g-locs g-locs)
+        (g-loccnt g-loccnt))
+       (d-pushargs (cdr v-form))
+       (d-calldirect '_Ibindvars (length (cdr v-form)))))
+
+(defun c-internal-unbind-vars nil
+   (let ((g-locs g-locs)
+        (g-loccnt g-loccnt))
+       (d-pushargs (cdr v-form))
+       (d-calldirect '_Iunbindvars (length (cdr v-form)))))
+
+;--- cc-quote : compile a "quote" expression
+; 
+; if we are just looking to set the ; cc, we just make sure 
+; we set the cc depending on whether the expression quoted is
+; nil or not.
+(defun cc-quote nil
+   (let ((arg (cadr v-form))
+        argloc)
+       (if (null g-loc) 
+          then (if (and (null arg) (cdr g-cc))
+                   then (e-goto (cdr g-cc))
+                elseif (and arg (car g-cc))
+                   then (e-goto (car g-cc))
+                elseif (null g-cc)
+                   then (comp-warn "losing the value of this expression "
+                                   (or v-form)))
+          else (d-move (d-loclit arg nil) g-loc)
+               (d-handlecc))))
+
+;--- c-setarg :: set a lexpr's arg
+; form is (setarg index value)
+;
+(defun c-setarg nil
+   (if (not (eq 'lexpr g-ftype))
+       then (comp-err "setarg only allowed in lexprs"))
+   (if (and fl-inter (eq (length (cdr v-form)) 3))     ; interlisp setarg
+       then (if (not (eq (cadr v-form) (car g-args)))
+               then (comp-err "setarg: can only compile local setargs "
+                              v-form)
+               else (setq v-form (cdr v-form))))
+   ; compile index into fixnum-reg, was (d-pushargs (list (cadr v-form)))
+   (let ((g-cc) (g-ret)
+        (g-loc '#.fixnum-reg))
+       (d-exp (cadr v-form)))
+   (let ((g-loc 'reg)
+        (g-cc nil)
+        (g-ret nil))
+       (d-exp (caddr v-form)))
+   #+for-vax
+   (progn
+       (e-sub3 `(* -4 #.olbot-reg) '(0 #.fixnum-reg) '#.fixnum-reg)
+       (e-move 'r0 '(-8 #.olbot-reg #.fixnum-reg)))
+   #+for-68k
+   (progn
+       (e-sub `(-4 #.olbot-reg) '#.fixnum-reg)
+       (e-write3 'lea '(% -8 #.olbot-reg #.fixnum-reg) 'a5)
+       (e-move 'd0 '(0 a5))))
+
+;--- cc-stringp :: check for string ness
+;
+(defun cc-stringp nil
+  (d-typesimp (cadr v-form) #.(immed-const 0)))
+
+;--- cc-symbolp :: check for symbolness
+;
+(defun cc-symbolp nil
+  (d-typesimp (cadr v-form) #.(immed-const 1)))
+
+;--- c-return :: compile a "return" statement
+;
+(defun c-return nil
+   ; value is always put in reg
+   (let ((g-loc 'reg)
+        g-cc
+        g-ret)
+       (d-exp (cadr v-form)))
+
+   ; if we are doing a non local return, compute number of specials to unbind
+   ; and locals to pop
+   (if (car g-labs)
+       then (e-goto (caar g-labs))
+       else (do ((loccnt 0)            ;; locals
+                (speccnt 0)            ;; special
+                (catcherrset 0)                ;; catch/errset frames
+                (ll g-labs (cdr ll))
+                (locs g-locs))
+               ((null ll) (comp-err "return used not within a prog or do"))
+               (if (car ll)
+                   then  (comp-note g-fname ": non local return used ")
+                        ; unbind down to but not including
+                        ; this frame.
+                        (if (greaterp loccnt 0)
+                            then (e-pop loccnt))
+                        (if (greaterp speccnt 0)
+                            then (e-unshallowbind speccnt))
+                        (if (greaterp catcherrset 0)
+                            then (comp-note
+                                     g-fname
+                                     ": return through a catch or errset"
+                                     v-form)
+                                 (do ((i 0 (1+ i)))
+                                     ((=& catcherrset i))
+                                     (d-popframe)))
+                        (e-goto (caar ll))
+                        (return)
+                   else ; determine number of locals and special on
+                        ; stack for this frame, add to running
+                        ; totals
+                        (do ()
+                            ((dtpr (car locs))
+                             (if (eq 'catcherrset (caar locs)) ; catchframe
+                                 then (incr catcherrset)
+                              elseif (eq 'progv (caar locs))
+                                 then (comp-err "Attempt to 'return' through a progv"))
+                             (setq speccnt (+ speccnt (cdar locs))
+                                   locs (cdr locs)))
+                            (incr loccnt)
+                            (setq locs (cdr locs)))))))
+        
+; c-rplaca :: compile a "rplaca" expression
+;
+#+for-vax
+(defun c-rplaca nil
+  (let ((ssimp (d-simple (caddr v-form)))
+       (g-ret nil))
+       (let ((g-loc (if ssimp then 'reg else 'stack))
+            (g-cc nil))
+           (d-exp (cadr v-form)))
+       (if (null ssimp)
+          then (push nil g-locs)
+               (incr g-loccnt)
+               (let ((g-loc 'r1)
+                     (g-cc nil))
+                   (d-exp (caddr v-form)))
+               (d-move 'unstack 'reg)
+               (unpush g-locs)
+               (decr g-loccnt)
+               (e-move 'r1 '(4 r0))
+          else (e-move (e-cvt ssimp)  '(4 r0)))
+       (d-clearreg)))          ; cant tell what we are clobbering
+
+#+for-68k
+(defun c-rplaca nil
+   (let ((ssimp (d-simple (caddr v-form)))
+        (g-ret nil))
+       (makecomment `(c-rplaca starting :: v-form = ,v-form))
+       (let ((g-loc (if ssimp then 'areg else 'stack))
+            (g-cc nil))
+          (d-exp (cadr v-form)))
+       (if (null ssimp)
+          then (push nil g-locs)
+               (incr g-loccnt)
+               (let ((g-loc 'd1)
+                     (g-cc nil))
+                   (d-exp (caddr v-form)))
+               (d-move 'unstack 'areg)
+               (unpush g-locs)
+               (decr g-loccnt)
+               (e-move 'd1 '(4 a0))
+          else (e-move (e-cvt ssimp)  '(4 a0)))
+       (e-move 'a0 'd0)
+       (d-clearreg)
+       (makecomment `(c-rplaca done))))
+
+; c-rplacd :: compile a "rplacd" expression
+;
+#+for-vax
+(defun c-rplacd nil
+  (let ((ssimp (d-simple (caddr v-form)))
+       (g-ret nil))
+       (let ((g-loc (if ssimp then 'reg else 'stack))
+            (g-cc nil))
+           (d-exp (cadr v-form)))
+       (if (null ssimp)
+          then (push nil g-locs)
+               (incr g-loccnt)
+               (let ((g-loc 'r1)
+                     (g-cc nil))
+                   (d-exp (caddr v-form)))
+               (d-move 'unstack 'reg)
+               (unpush g-locs)
+               (decr g-loccnt)
+               (e-move 'r1 '(0 r0))
+          else (e-move (e-cvt ssimp)  '(0 r0)))
+       (d-clearreg)))
+
+#+for-68k
+(defun c-rplacd nil
+   (let ((ssimp (d-simple (caddr v-form)))
+        (g-ret nil))
+       (makecomment `(c-rplacd starting :: v-form = ,v-form))
+       (let ((g-loc (if ssimp then 'areg else 'stack))
+            (g-cc nil))
+          (d-exp (cadr v-form)))
+       (if (null ssimp)
+          then (push nil g-locs)
+               (incr g-loccnt)
+               (let ((g-loc 'd1)
+                     (g-cc nil))
+                   (d-exp (caddr v-form)))
+               (d-move 'unstack 'areg)
+               (unpush g-locs)
+               (decr g-loccnt)
+               (e-move 'd1 '(0 a0))
+          else (e-move (e-cvt ssimp) '(0 a0)))
+       (e-move 'a0 'd0)
+       (d-clearreg)
+       (makecomment `(d-rplacd done))))
+
+;--- cc-setq :: compile a "setq" expression
+;
+(defun cc-setq nil
+  (let (tmp tmp2)
+       (if (oddp (length (cdr v-form)))
+          then (comp-err "wrong number of args to setq "
+                         (or v-form))
+       elseif (cdddr v-form)           ; if multiple setq's
+          then (do ((ll (cdr v-form) (cddr ll))
+                    (g-loc)
+                    (g-cc nil))
+                   ((null (cddr ll)) (setq tmp ll))
+                   (setq g-loc (d-locv (car ll)))
+                   (d-exp (cadr ll))
+                   (d-clearuse (car ll)))
+       else (setq tmp (cdr v-form)))
+
+       ; do final setq
+       (let ((g-loc (d-locv (car tmp)))
+            (g-cc (if g-loc then nil else g-cc))
+            (g-ret nil))
+           (d-exp (cadr tmp))
+           (d-clearuse (car tmp)))
+       (if g-loc
+          then (d-move (setq tmp2 (d-locv (car tmp))) g-loc)
+               (if g-cc
+                   then #+for-68k (d-cmpnil tmp2)
+                        (d-handlecc)))))
+
+; cc-typep :: compile a "typep" expression
+; 
+; this returns the type of the expression, it is always non nil
+;
+#+for-vax
+(defun cc-typep nil
+  (let ((argloc (d-simple (cadr v-form)))
+       (g-ret))
+       (if (null argloc)
+          then (let ((g-loc 'reg) g-cc)
+                   (d-exp (cadr v-form)))
+               (setq argloc 'reg))
+       (if g-loc
+          then (e-write4 'ashl '($ -9) (e-cvt argloc) 'r0)
+               (e-write3 'cvtbl "_typetable+1[r0]" 'r0)
+               (e-move "_tynames+4[r0]" 'r0)
+               (e-move '(0 r0) (e-cvt g-loc)))
+       (if (car g-cc) then (e-goto (car g-cc)))))
+
+#+for-68k
+(defun cc-typep nil
+  (let ((argloc (d-simple (cadr v-form)))
+       (g-ret))
+       (if (null argloc) 
+          then (let ((g-loc 'reg) g-cc)
+                   (d-exp (cadr v-form)))
+               (setq argloc 'reg))
+       (if g-loc
+          then (e-move (e-cvt argloc) 'd0)
+               (e-sub '#.nil-reg 'd0)
+               (e-write3 'moveq '($ 9) 'd1)
+               (e-write3 'asrl 'd1 'd0)
+               (e-write3 'lea '"_typetable+1" 'a5)
+               (e-add 'd0 'a5)
+               (e-write3 'movb '(0 a5) 'd0)
+               (e-write2 'extw 'd0)
+               (e-write2 'extl 'd0)
+               (e-write3 'asll '($ 2) 'd0)
+               (e-write3 'lea "_tynames+4" 'a5)
+               (e-add 'd0 'a5)
+               (e-move '(0 a5) 'a5)
+               (e-move '(0 a5) (e-cvt g-loc)))
+       (if (car g-cc) then (e-goto (car g-cc)))))
+
+; cm-symeval :: compile a symeval expression.
+; the symbol cell in franz lisp is just the cdr.
+;
+(defun cm-symeval nil
+  `(cdr ,(cadr v-form)))
+
+; c-*throw :: compile a "*throw" expression
+;
+; the form of *throw is (*throw 'tag 'val) .
+; we calculate and stack the value of tag, then calculate val 
+; we call Idothrow to do the actual work, and only return if the
+; throw failed.
+;
+(defun c-*throw nil
+  (let ((arg2loc (d-simple (caddr v-form)))
+       g-cc
+       g-ret
+       arg1loc)
+       ; put on the C runtime stack value to throw, and
+       ; tag to throw to.
+       (if arg2loc
+          then (if (setq arg1loc (d-simple (cadr v-form)))
+                   then (C-push (e-cvt arg2loc))
+                        (C-push (e-cvt arg1loc))
+                   else (let ((g-loc 'reg))
+                            (d-exp (cadr v-form))      ; calc tag
+                            (C-push (e-cvt arg2loc))
+                            (C-push (e-cvt 'reg))))
+          else (let ((g-loc 'stack))
+                   (d-exp (cadr v-form))       ; calc tag to stack
+                   (push nil g-locs)
+                   (incr g-loccnt)
+                   (setq g-loc 'reg)
+                   (d-exp (caddr v-form))      ; calc value into reg
+                   (C-push (e-cvt 'reg))
+                   (C-push (e-cvt 'unstack))
+                   (unpush g-locs)
+                   (decr g-loccnt)))
+       ; now push the type of non local go we are doing, in this case
+       ; it is a C_THROW
+       (C-push '($ #.C_THROW))
+       #+for-vax
+       (e-write3 'calls '$3 '_Inonlocalgo)
+       #+for-68k
+       (e-quick-call '_Inonlocalgo)))
+
+;--- cm-zerop ::  convert zerop to a quick test
+; zerop is only allowed on fixnum and flonum arguments.  In both cases,
+; if the value of the first 32 bits is zero, then we have a zero.
+; thus we can define it as a macro:
+#+for-vax
+(defun cm-zerop nil
+  (cond ((atom (cadr v-form))
+        `(and (null (cdr ,(cadr v-form))) (not (bigp ,(cadr v-form)))))
+       (t (let ((gnsy (gensym)))
+               `((lambda (,gnsy)
+                         (and (null (cdr ,gnsy)) 
+                               (not (bigp ,gnsy))))
+                 ,(cadr v-form))))))
+
+#+for-68k
+(defun cm-zerop nil
+   (cond ((atom (cadr v-form))
+         `(and (=& 0 ,(cadr v-form))   ;was (cdr ,(cadr v-form))
+               (not (bigp ,(cadr v-form)))))
+        (t (let ((gnsy (gensym)))
+               `((lambda (,gnsy)
+                     (and (=& 0 ,gnsy)         ;was (cdr ,gnsy)
+                          (not (bigp ,gnsy))))
+                 ,(cadr v-form))))))
diff --git a/usr/src/ucb/lisp/liszt/lversion.l b/usr/src/ucb/lisp/liszt/lversion.l
new file mode 100644 (file)
index 0000000..e2a279b
--- /dev/null
@@ -0,0 +1,19 @@
+;; lversion.l
+;;                             -[Fri Aug 19 13:22:41 1983 by jkf]-
+;;
+;; this defines this symbols:
+;;   this-liszt-version-built: ctime string which tells when this liszt
+;;     was built.
+;;   compiler-name: the banner printed out when liszt starts up
+
+;; this file is not sccsed because it only contains version number
+;; information.
+
+(setq this-liszt-version-built (status ctime))
+
+(setq compiler-name
+   (concat "Liszt "
+          #.(cond ((status feature for-vax) "vax")
+                  ((status feature for-68k) "68000")
+                  (t "unknown machine"))
+          " version 8.36"))
diff --git a/usr/src/ucb/lisp/liszt/lxref.l b/usr/src/ucb/lisp/liszt/lxref.l
new file mode 100644 (file)
index 0000000..c7ac687
--- /dev/null
@@ -0,0 +1,498 @@
+(setq rcs-lxref-ident
+   "$Header: lxref.l,v 1.1 83/01/26 12:16:24 jkf Exp $")
+
+;------   lxref: lisp cross reference program        
+;-- author: j foderaro
+;  This program generates a cross reference listing of a set of one or
+; more lisp files.  It reads the output of cross reference files 
+; generated by the compiler.  These files usually have the extension .x .
+; the .x files are lisp readable.  There format is:
+; The first s-expression is (File  <filename>) where <filename> is the
+; name of the lisp source file.
+; Then there is one s-expression for each function (including macros)
+; which is defined in the file.  The car of each expression is the function
+; name, the cadr is the function type and the cddr is a list of those
+; functions called
+; 
+; lxref can be run from the command level
+; % lxref foo.x bar.x
+; or in this way
+; % lxref
+; -> (lxref foo.x bar.x)
+;
+; There is one option, that is changing the ignorelevel.  If a function
+; is called by more than ignorelevel functions then all those functions
+; are listed, instead a summary of the number of calls is printed.  This
+; is useful for preventing  the printing of massive lists for common
+; system functions such as setq.
+; To change the ignorelevel to 40 you would type:
+;
+; % lxref -40 foo.x bar.x
+;
+;; internal data structures used in lxref:
+;   funcs : list of functions mentioned either as caller or as callee
+;  on each function in funcs, the property list contains some of these
+;  indicators:
+;      i-seen : always contains t [this is so we can avoid (memq foo funcs)
+;      i-type : list of the types this function was declared as. In 1-1
+;               corresp with i-home
+;      i-home : list of files this function was declared in. In 1-1 corresp
+;               with i-type
+;      i-callers: list of functions calling this function
+
+
+
+
+
+; insure we have plenty of space to grow into
+(opval 'pagelimit 9999)
+
+
+(declare (special xref-readtable width ignorefuncs ignorelevel readtable 
+                 user-top-level poport i-seen i-type i-callers docseen
+                 i-Chome i-Doc i-home funcs
+                 callby-marker debug-mode
+                 anno-off-marker
+                 anno-on-marker))
+
+(setq ignorelevel 50)
+(setq callby-marker   (exploden ";.. ")        
+      anno-off-marker (exploden ";.-") 
+      anno-on-marker  (exploden ";.+"))        
+
+;--- xrefinit :: called automatically upon startup
+;
+(def xrefinit
+   (lambda nil
+      (let ((args (command-line-args))
+           (retval))
+        ; readtable should be the same as it was when liszt wrote
+        ; the xref file
+        (if args
+           then (signal 2 'exit)       ; die on interrupt
+                (signal 15 'exit)      ; die on sigterm
+                (setq user-top-level nil)
+                (let ((retval (car (errset (funcall 'lxref args)))))
+                   (exit (if retval thenret else -1)))
+           else (patom "Lxref - lisp cross reference program")
+                (terpr poport)
+                (setq user-top-level nil)))))
+
+(setq user-top-level 'xrefinit)
+
+;--- lxref :: main function
+;
+(defun lxref fexpr (files)
+   (prog (p funcs i-seen i-home i-type i-callers filenm caller callee name
+           home type caller temp fname callers clength i-Chome i-Doc docseen
+           Chome Doc anno-mode debug-mode)
+
+      (setq xref-readtable (makereadtable t))
+      (setq i-seen (gensym) i-home (gensym) i-type (gensym)
+           i-callers (gensym) i-Chome (gensym) i-Doc (gensym))
+
+      ; check for the ignorelevel option
+      ; it must be the first option given.
+      ;
+      (If (and files (eq #/- (getcharn (car files) 1)))
+        then (If (fixp
+                    (setq temp (readlist (cdr (explode (car files))))))
+                then (setq ignorelevel temp)
+                     (setq files (cdr files))))
+
+      ; process all files.  if a -a is seen, go into annotate mode.
+      ; otherwise generate an xref file.
+      ;
+      (do ((ii files (cdr ii)))
+         ((null ii))
+         (if (eq '-d (car ii))
+            then (setq debug-mode t)
+          elseif anno-mode
+            then (process-annotate-file (car ii))
+          elseif (eq '-a (car ii))
+            then (setq anno-mode t)
+            else (process-xref-file (car ii))))
+      (if (not anno-mode) (generate-xref-file))
+      (return 0)))
+
+;.. process-xref-file
+(defun illegal-file (name)
+   (msg "File " name " is not a valid cross reference file" N))
+
+;--- process-xref-file :: scan the information in an xref file
+; if the name ends in .l then change it to .x
+;
+;.. lxref
+(defun process-xref-file (name)
+   (if debug-mode then (msg "process-xref-file: " name N))
+   (let (p fname filenm)
+      ; convert foo.l to foo.x
+      (setq fname (nreverse (exploden name)))
+      (If (and (eq #/l (car fname)) (eq #/. (cadr fname)))
+        then (setq fname (implode (nreverse (cons #/x (cdr fname)))))
+        else (setq fname name))
+
+      ; now look for foo or foo.x
+      (If (and (null (errset (setq p (infile fname)) nil))
+              (null (errset (setq p (infile (concat fname ".x"))) nil)))
+        then (msg "Couldn't open " name N)
+        else (setq filenm (car (errset (read p))))
+             (If (dtpr filenm)
+                then (If (eq 'File (car filenm))
+                        then (setq filenm (cadr filenm))
+                             (process-File p filenm)
+                      elseif (eq 'Chome (car filenm))
+                        then (process-Chome p)
+                      elseif (eq 'Doc (car filenm))
+                        then (setq docseen t) (process-Doc p)
+                        else (illegal-file name))
+                else (illegal-file name))
+             (close p))))
+
+
+;--- process-File :: process an xref file from liszt
+;
+;.. process-xref-file
+(defun process-File (p filenm)
+   (let ((readtable xref-readtable))
+      (do ((jj (read p) (read p))
+          (caller)
+          (callee))
+         ((null jj) (close p))
+         (setq caller (car jj))
+         (If (not (get caller i-seen))
+            then (putprop caller t i-seen)
+                 (push caller funcs))  ; add to global list
+         ; remember home of this function (and allow multiple homes)
+         (push filenm (get caller i-home))
+
+         ; remember type of this function (and allow multiple types)
+         (push (cadr jj) (get caller i-type))
+
+         ; for each function the caller calls
+         (do ((kk (cddr jj) (cdr kk)))
+             ((null kk))
+             (setq callee (car kk))
+             (If (not (get callee i-seen)) then (putprop callee t i-seen)
+                 (push callee funcs))
+             (push (cons caller filenm) (get callee i-callers))))))
+
+;.. process-xref-file
+(defun process-Chome (p)
+   (do ((jj (read p) (read p))
+       (caller))
+       ((null jj) (close p))
+       (setq caller (car jj))
+       (If (not (get caller i-seen))
+          then (putprop caller t i-seen)
+          (push caller funcs)) ; add to global list
+       ; remember home of this function (and allow multiple homes)
+       (putprop caller (cons (cdr jj) (get caller i-Chome)) i-Chome)))
+
+;--- process-Doc :: process a Doc file
+;
+; A doc file begins with an entry (Doc).
+; subsequent entries are (Name File)  and this means that function
+; Name is defined in file File.  This type of file is generated
+; by a sed and awk script passing over the franz manual. (see the
+; Makefile in the doc directory).
+;
+;.. process-xref-file
+(defun process-Doc (p)
+   (do ((jj (read p) (read p))
+       (caller))
+       ((null jj) (close p))
+       (setq caller (car jj))
+       (If (not (get caller i-seen))
+          then (putprop caller t i-seen)
+          (push caller funcs)) ; add to global list
+       ; remember home of this function (and allow multiple homes)
+       (putprop caller (cons (cadr jj) (get caller i-Doc)) i-Doc)))
+
+;.. generate-xref-file
+(defun terprchk (wid)
+  (cond ((> (setq width (+ wid width)) 78.) 
+        (terpr)
+        (patom "       ")
+        (setq width (+ 8 wid)))))
+
+; determine type of function
+;.. generate-xref-file
+(defun typeit (fcn)
+  (cond ((bcdp fcn) (getdisc fcn))
+       ((dtpr fcn) (car fcn))))
+
+
+;.. lxref
+(defun generate-xref-file ()
+   ; sort alphabetically
+   (setq funcs (sort funcs 'alphalessp))
+
+   ; now print out the cross reference
+   (do ((ii funcs (cdr ii))
+       (name) (home) (type) (callers) (Chome) (Doc) (clength))
+       ((null ii))
+       (setq name (car ii)
+            home (get name i-home)
+            type (get name i-type)
+            callers (get name i-callers)
+            Chome (get name i-Chome)
+            Doc (get name i-Doc))
+
+       (If (lessp (setq clength (length callers)) ignorelevel)
+         then (setq callers (sortcar callers 'alphalessp)))
+
+       (do ((xx Chome (cdr xx)))
+          ((null xx))
+          (setq home (cons (concat "<C-code>:" (caar xx))
+                           home)
+                type (cons (cadar xx) type)))
+
+       (If (null home)
+         then (setq home (If (getd name)
+                            then (setq type
+                                       (ncons (typeit (getd name))))
+                                 '(Franz-initial)
+                            else '(Undefined))))
+
+       (patom name)
+       (patom "        ")
+
+
+       (If (null (cdr type))
+         then (patom (car type))
+              (patom " ")
+              (patom (car home))
+         else (patom "Mult def: ")
+              (mapcar '(lambda (typ hom)
+                          (patom typ)
+                          (patom " in ")
+                          (patom hom)
+                          (patom ", "))
+                      type
+                      home))
+
+
+       (If docseen
+         then (If Doc then (msg "  [Doc: " (If (cdr Doc) then Doc
+                                              else (car Doc)) "]")
+                 else (msg "  [**undoc**]")))
+       (If (null callers) then (msg "  *** Unreferenced ***"))
+       (terpr)
+       (patom "        ")
+       (cond ((null callers))
+            ((not (lessp clength ignorelevel))
+             (patom "Called by ")
+             (print clength)
+             (patom " functions"))
+            (t (do ((jj callers (cdr jj))
+                    (calle)
+                    (width 8))
+                   ((null jj))
+                   ; only print name if in same file
+                   (setq calle (caar jj))
+                   (cond ((memq (cdar jj) home)
+                          (terprchk (+ (flatc calle) 2))
+                          (patom calle))
+                         (t (terprchk (+ (flatc calle) 6 (flatc (cdar jj))))
+                            (patom calle)
+                            (patom " in ")
+                            (patom (cdar jj))))
+                   (If (cdr jj) then (patom ", ")))))
+       (terpr)
+       (terpr)
+       botloop ))
+
+
+;--- annotate code
+
+
+                  
+;--- process-annotate-file :: anotate a file
+;
+;.. lxref
+(defun process-annotate-file (filename)
+   (let (sourcep outp)
+      ; make sure file exists and write annotate file as a
+      ; file with the prefix #,
+      (if (null (errset (setq sourcep (infile filename))))
+        then (msg "will ignore that file " N)
+        else ; will write to file.A (erasing the final l)
+             (let ((filen (concat "#," filename)))
+                (setq outp (outfile filen))
+                (anno-it sourcep outp)
+                (close outp)
+                ; now mv the original filename to #dfilename
+                ; and the annotated file to the original file
+                (let ((oldcopy (concat "#." filename)))
+                   (if (null (errset
+                                (progn (if (probef oldcopy)
+                                          then (sys:unlink oldcopy))
+                                       (sys:link filename oldcopy)
+                                       (sys:unlink filename)
+                                       (sys:link filen filename)
+                                       (sys:unlink filen))))
+                      then (msg "An error occured while mving files around "
+                                N
+                                "files possibly affected "
+                                filename oldcopy filen)))))))
+
+
+;.. process-annotate-file
+(defun anno-it (inp outp)
+   (do ((xx (read-a-line inp) (read-a-line inp))
+       (anno-it t))
+       ((null xx))
+       (if (match xx 1 callby-marker)  ; flush anno lines
+         then (flush-a-line outp inp)
+       elseif (match xx 1 anno-off-marker)
+         then (setq anno-it nil)       ; ';#-'  turns off annotating
+              (write-a-line xx outp inp)
+       elseif (match xx 1 anno-on-marker)
+         then (setq anno-it t)
+              (write-a-line xx outp inp)
+         else (if anno-it then (anno-check xx outp))
+              (write-a-line xx outp inp))))
+
+
+;;; file reading code for annotate function
+; lines are read with (read-a-line port).  It will read up to the
+; first 127 characters in the line, returning a hunk whose cxr 0 is the
+; max(index) + 1 of the characters in the hunk.  the oversize-line flag
+; will be set if there are still more character to be read from this line.
+;
+; the line should be printed by calling (print-a-line buffer) or if it isn't
+; to be printed, (flush-a-line) should be called (which will check the
+; oversize-line flag and flush unread input too).
+;
+(declare (special inp-buffer oversize-line))
+
+(setq inp-buffer (makhunk 128))
+
+;.. anno-it
+(defun read-a-line (port)
+   (setq oversize-line nil)
+   (do ((i 1 (1+ i))
+       (ch (tyi port) (tyi port)))
+       ((or (eq #\newline ch)
+           (eq #\eof ch))
+       (if (or (eq #\newline ch) (>& i 1))
+          then (rplacx 0 inp-buffer i)         ; store size
+               inp-buffer                      ; return buffer
+          else nil))   ; return nil upon eof
+       (rplacx i inp-buffer ch)
+       (if (>& i 126)
+         then (setq oversize-line t)
+              (rplacx 0 inp-buffer (1+ i))
+              (return inp-buffer))))
+
+;--- write-a-line :: write the given buffer and check for oversize-line
+;
+;.. anno-it
+(defun write-a-line (buf oport iport)
+   (do ((max (cxr 0 buf))
+       (i 1 (1+ i)))
+       ((not (<& i max))
+       (if oversize-line
+           then (oversize-check oport iport t)
+           else (terpr oport)))
+       (tyo (cxr i buf) oport)))
+
+;.. anno-it
+(defun flush-a-line (oport iport)
+   (oversize-check oport iport nil))
+
+;.. flush-a-line, write-a-line
+(defun oversize-check (oport iport printp)
+   (if oversize-line
+      then (do ((ch (tyi iport) (tyi iport)))
+              ((or (eq ch #\eof) (eq ch #\newline))
+               (cond ((and printp (eq ch #\newline))
+                      (tyo ch oport))))
+              (if printp then (tyo ch oport)))))
+
+       
+                      
+;.. anno-it
+(defun anno-check (buffer outp)
+   (if (match buffer 1 '(#\lpar #/d #/e #/f))
+      then (let (funcname)
+             (if (setq funcname (find-func buffer))
+                 (let ((recd (get funcname i-callers)))
+                    (if recd
+                       then (printrcd recd outp)))))))
+
+;--- printrcd :: print a description
+;
+;.. anno-check
+(defun printrcd (fcns port)
+   (let ((functions (sortcar fcns 'alphalessp)))
+      (print-rec functions port 0)))
+
+;.. print-rec, printrcd
+(defun print-rec (fcns p wide)
+   (if fcns
+      then (let ((size (flatc (caar fcns))))
+             (if (>& (+ size wide 2) 78)
+                then (msg (P p) N )
+                     (setq wide 0))
+             (if (=& wide 0)
+                then (mapc '(lambda (x) (tyo x p)) callby-marker)
+                     (setq wide (length callby-marker)))
+             (if (not (=& wide 4))
+                then (msg (P p) ", ")
+                     (setq wide (+ wide 2)))
+             (msg (P p) (caar fcns))
+             (print-rec (cdr fcns) p (+ wide size 2)))
+      else (msg (P p) N)))
+
+                     
+                   
+;--- match :: try to locate pattern in buffer
+; start at 'start' in buf.
+;.. anno-check, anno-it, match
+(defun match (buf start pattern)
+   (if (null pattern)
+      then t
+    elseif (and (<& start (cxr 0 buf))
+           (eq (car pattern) (cxr start buf)))
+      then (match buf (1+ start) (cdr pattern))))
+
+;--- find-func :: locate function name on line
+;
+;.. anno-check
+(defun find-func (buf)
+   ; first locate first space or tab
+   (do ((i 1 (1+ i))
+       (max (cxr 0 buf))
+       (die))
+       ((or (setq die (not (<& i max)))
+           (memq (cxr i buf) '(#\space #\tab)))
+       (if die
+          then nil     ; can find it, so give up
+          else ; find first non blank
+               (do ((ii i (1+ ii)))
+                   ((or (setq die (not (<& ii max)))
+                        (not (memq (cxr ii buf) '(#\space #\tab))))
+                    (if (or die (eq (cxr ii buf) #\lpar))
+                       then nil
+                       else ; fid first sep or left paren
+                            (do ((iii (1+ ii) (1+ iii)))
+                                ((or (not (<& iii max))
+                                     (memq (cxr iii buf)
+                                           '(#\space #\tab #\lpar)))
+                                 (implode-fun buf ii (1- iii)))))))))))
+
+;--- implode-fun :: return implode of everything between from and to in buf
+;
+;.. find-func
+(defun implode-fun (buf from to)
+   (do ((xx (1- to) (1- xx))
+       (res (list (cxr to buf)) (cons (cxr xx buf) res)))
+       ((not (<& from xx))
+       (implode (cons (cxr from buf) res)))))
+
+
+
+
+
diff --git a/usr/src/ucb/lisp/liszt/tlev.l b/usr/src/ucb/lisp/liszt/tlev.l
new file mode 100644 (file)
index 0000000..f5b416a
--- /dev/null
@@ -0,0 +1,1057 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file tlev
+   "$Header: tlev.l,v 1.13 83/09/12 15:25:29 layer Exp $")
+
+;;; ----       t l e v                         top level interface
+;;;
+;;;                            -[Fri Sep  2 21:50:34 1983 by layer]-
+
+;--- lisztinit : called upon compiler startup. If there are any args
+;             on the command line, we build up a call to liszt, which
+;             will do the compile. Afterwards we exit.
+;
+(def lisztinit
+   (lambda nil
+      (setq fl-asm nil)                ; insure it as correct value in case of int
+      (let ((args (command-line-args)))
+        (if args
+           then (signal 2 'liszt-interrupt-signal)  ; die on int
+                (signal 15 'liszt-interrupt-signal)  ; die on sigterm
+                (setq user-top-level nil)
+                (exit (apply 'liszt args))
+           else (patom compiler-name)
+                (patom " [")(patom franz-minor-version-number)(patom "]")
+                (terpr poport)
+                (setq user-top-level nil)))))
+
+(setq user-top-level 'lisztinit)
+\f
+;--- liszt - v-x : list containing file name to compile and optionaly
+;               and output file name for the assembler source.
+;
+(def liszt
+  (nlambda (v-x)
+          (prog (piport v-root v-ifile v-sfile v-ofile 
+                        vp-ifile vp-sfile vps-crap
+                        vps-include vns-include
+                        asm-exit-status ntem temgc temcp
+                        rootreal g-arrayspecs out-path
+                        g-decls g-stdref pre-eval include-files
+                        g-fname g-trueop g-falseop g-didvectorcode
+                        tem temr starttime startptime startgccount
+                        fl-asm fl-warn fl-verb fl-inter fl-xref fl-uci
+                        fl-run fl-case fl-anno g-optionalp
+                        liszt-process-forms in-line-lambda-number
+                        g-skipcode g-dropnpcnt g-complrname)
+
+                ;in case "S" switch given, set asm-exit-status
+                ;  to 0 (so garbage won't be returned).
+                (setq asm-exit-status 0)
+
+                ; turn on monitoring if it exists
+                #+monitoring
+                (errset (progn (monitor t)     ; turn it on
+                               (print 'monitor-on)
+                               (terpr))
+                        nil)
+                (setq starttime (sys:time)   ; real time in seconds
+                      startptime (ptime)
+                      startgccount $gccount$)
+                (setq in-line-lambda-number (sys:time))
+                (cond ((null (boundp 'internal-macros))
+                       (setq internal-macros nil)))
+                (cond ((null (boundp 'macros))
+                       (setq macros nil)))
+                (setq er-fatal 0)
+                (setq vps-include nil  
+                      vns-include nil)  ;stack of ports and names
+                (setq twa-list nil)
+                (setq liszt-eof-forms nil)
+
+                ; look for lisztrc file and return if error occured
+                ; in reading it
+                (cond ((eq (do-lisztrc-check) 'error)
+                       (return 1)))
+                
+                ; set up once only g variables
+                (setq g-comments nil
+                      g-current nil            ; current function name
+                      g-funcs nil
+                      g-lits nil
+                      g-trueloc nil
+                      g-tran nil
+                      g-allf nil               ; used in xrefs
+                      g-reguse #+for-vax (copy '((r4 0 . nil) (r3 0 . nil)
+                                                 (r2 0 . nil); (r7 0 . nil)
+                                                 (r1 0 . nil)))
+                               #+for-68k (copy '((a0 0 . nil) (a1 0 . nil)
+                                                 (d1 0 . nil) (d2 0 . nil)
+                                                 (d4 0 . nil) (d5 0 . nil)))
+                      g-trancnt 0
+                      g-ignorereg nil
+                      g-trueop  #+for-vax 'jneq        ; used in e-gotot
+                                #+for-68k 'jne
+                      g-falseop #+for-vax 'jeql        ; used in e-gotonil
+                                #+for-68k 'jeq
+                      g-compfcn nil
+                      g-litcnt 0)
+                (setq g-spec (gensym 'S))      ; flag for special atom
+                (setq g-fname "")              ; no function yet
+                (setq special nil)             ; t if all vrbs are special
+                (setq g-functype (gensym)
+                      g-vartype  (gensym)
+                      g-bindtype (gensym)
+                      g-calltype (gensym)
+                      g-bindloc  (gensym)
+                      g-localf   (gensym)
+                      g-arrayspecs (gensym)
+                      g-tranloc  (gensym)
+                      g-stdref   (gensym)
+                      g-optionalp (gensym))
+
+                ; declare these special
+
+                (sstatus feature complr)
+                (d-makespec 't)                ; always special
+
+                ; process input form
+                (setq fl-asm t         ; assembler file assembled
+                      fl-warn t        ; print warnings
+                      fl-verb t        ; be verbose
+                      fl-macl nil      ; compile maclisp file
+                      fl-anno nil      ; annotate 
+                      fl-inter nil     ; do interlisp compatablity
+                      fl-tty nil       ; put .s on tty
+                      fl-comments nil    ; put in comments
+                      fl-profile nil   ; profiling
+                      fl-tran    t     ; use transfer tables
+                      fl-vms   nil     ; vms hacks
+                      fl-case  nil     ; trans uc to lc
+                      fl-xref  nil     ; xrefs
+                      fl-run   nil     ; autorun capability
+                      fl-uci   nil     ; uci lisp compatibility
+                      )
+
+                ; look in the environment for a LISZT variable
+                ; if it exists, make it the first argument 
+                (if (not (eq '|| (setq tem (getenv 'LISZT))))
+                    then (setq v-x (cons (concat "-" tem) v-x)))
+
+                (do ((i v-x (cdr i)))  ; for each argument
+                    ((null i))
+                    (setq tem (aexplodec (car i)))
+
+                    (cond ((eq '- (car tem))   ; if switch
+                           (do ((j (cdr tem) (cdr j)))
+                               ((null j))
+                               (cond ((eq 'S (car j)) (setq fl-asm nil))
+                                     ((eq 'C (car j)) (setq fl-comments t))
+                                     ((eq 'm (car j)) (setq fl-macl t))
+                                     ((eq 'o (car j)) (setq v-ofile (cadr i)
+                                                            i (cdr i)))
+                                     ((eq 'e (car j)) (setq pre-eval (cadr i)
+                                                            i (cdr i)))
+                                     ((eq 'i (car j)) (push (cadr i)
+                                                            include-files)
+                                                      (pop i))
+                                     ((eq 'w (car j)) (setq fl-warn nil))
+                                     ((eq 'q (car j)) (setq fl-verb nil))
+                                     ((eq 'Q (car j)) (setq fl-verb t))
+                                     ((eq 'T (car j)) (setq fl-tty t))
+                                     ((eq 'a (car j)) (setq fl-anno t))
+                                     ((eq 'i (car j)) (setq fl-inter t))
+                                     ((eq 'p (car j)) (setq fl-profile t))
+                                     ((eq 'F (car j)) (setq fl-tran nil))
+                                     ((eq 'v (car j)) (setq fl-vms t))
+                                     ((eq 'r (car j)) (setq fl-run t))
+                                     ((eq 'x (car j)) (setq fl-xref t))
+                                     ((eq 'c (car j)) (setq fl-case t))
+                                     ((eq 'u (car j)) (setq fl-uci  t))
+                                     ((eq '- (car j)))  ; ignore extra -'s
+                                     (t (comp-gerr "Unknown switch: "
+                                                   (car j))))))
+                          ((null v-root)
+                           (setq temr (reverse tem))
+                           (cond ((and (eq 'l (car temr))
+                                       (eq '\. (cadr temr)))
+                                  (setq rootreal nil)
+                                  (setq v-root
+                                        (apply 'concat
+                                               (reverse (cddr temr)))))
+                                 (t (setq v-root (car i)
+                                          rootreal t))))
+
+                          (t (comp-gerr "Extra input file name: " (car i)))))
+
+                ;no transfer tables in vms
+                (cond (fl-vms (setq fl-tran nil)))
+
+                ; if verbose mode, print out the gc messages and
+                ; fasl messages, else turn them off.
+                (cond (fl-verb (setq $gcprint t
+                                     $ldprint t))
+                      (t (setq $gcprint nil
+                                $ldprint nil)))
+
+                ; eval arg after -e
+                (if pre-eval
+                   then (if (null (errset
+                                     (eval (readlist (exploden pre-eval)))))
+                           then (comp-gerr "-e form caused error: "
+                                           pre-eval)))
+
+                ; load file after -i arg
+                (if include-files
+                   then (catch
+                           (mapc
+                              '(lambda (file)
+                                  (if (null (errset (load file)))
+                                     then (comp-err
+                                             "error when loading -i file: "
+                                             file)))
+                              include-files)
+                           Comp-error))
+
+                ; -c says set reader to xlate uc to lc
+                (cond (fl-case (sstatus uctolc t)))
+
+                ; If we are a cross compiler, then don't try to
+                ; assemble our output...
+                ;
+                #+for-vax
+                (if (status feature 68k)
+                    then (setq fl-asm nil))
+                #+for-68k
+                (if (status feature vax)
+                    then (setq fl-asm nil))
+
+                ; now see what the arguments have left us
+                (cond ((null v-root)
+                       (comp-gerr "No file for input"))
+                      ((or (portp 
+                            (setq vp-ifile 
+                                  (car (errset (infile 
+                                                  (setq v-ifile 
+                                                        (concat v-root '".l"))) 
+                                               nil))))
+                           (and rootreal
+                                (portp
+                                 (setq vp-ifile
+                                       (car (errset 
+                                                (infile (setq v-ifile v-root))
+                                                nil)))))))
+                      (t (comp-gerr "Couldn't open the source file :"
+                                    (or v-ifile))))
+
+
+                ; determine the name of the .s file
+                ; strategy: if fl-asm is t (assemble) use (v-root).s
+                ;           else use /tmp/(PID).s
+                ;  
+                ; direct asm to tty temporarily
+                (setq v-sfile "tty")
+                (setq vp-sfile nil)
+                (if (null fl-tty) then
+                    (cond (fl-asm (setq v-sfile
+                                        (concat '"/tmp/Lzt"
+                                                         (boole 1 65535
+                                                                (sys:getpid))
+                                                         '".s")))
+                          (t (setq v-sfile
+                                   (if v-ofile
+                                       then v-ofile
+                                       else (concat v-root '".s")))))
+                    
+                    (cond ((not (portp (setq vp-sfile
+                                             (car (errset (outfile v-sfile)
+                                                          nil)))))
+                           (comp-gerr "Couldn't open the .s file: "
+                                      (or v-sfile)))))
+                                    
+                
+                ; determine the name of the .o file (object file)
+                ; strategy: if we aren't supposed to assemble the .s file
+                ;            don't worry about a name
+                ;           else if a name is given, use it
+                ;           else if use (v-root).o
+                ;  if profiling, use .o
+                (cond ((or v-ofile (null fl-asm)))             ;ignore
+                      ((null fl-profile) (setq v-ofile (concat v-root ".o")))
+                      (t (setq v-ofile (concat v-root ".o"))))
+
+                ; determine the name of the .x file (xref file)
+                ; strategy: if fl-xref and v-ofile is true, then use
+                ; v-ofile(minus .o).x, else use (v-root).x
+                ;
+                (if fl-xref
+                   then ; check for ending with .X for any X
+                        (setq v-xfile
+                              (if v-ofile
+                                 then (let ((ex (nreverse
+                                                   (exploden v-ofile))))
+                                         (if (eq #/. (cadr ex))
+                                            then (implode
+                                                    (nreverse
+                                                       `(#/x #/.
+                                                          ,@(cddr ex))))
+                                            else (concat v-ofile ".x")))
+                                 else (concat v-root ".x")))
+                        (if (portp
+                               (setq vp-xfile
+                                     (car (errset (outfile v-xfile)))))
+                           thenret
+                           else (comp-gerr "Can't open the .x file: "
+                                           v-xfile)))
+                (cond ((checkfatal) (return 1)))
+
+                ; g-complrname is a symbol which should be unique to
+                ; each fasl'ed file. It will contain the string which
+                ; describes the name of this file and the compiler
+                ; version.
+                (if fl-anno
+                   then (setq g-complrname (concat "fcn-in-" v-ifile))
+                        (Push g-funcs
+                              `(eval (setq ,g-complrname
+                                           ,(get_pname
+                                               (concat v-ifile
+                                                       " compiled by "
+                                                       compiler-name
+                                                       " on "
+                                                       (status ctime)))))))
+                                                       
+                
+                (setq readtable (makereadtable nil))   ; use new readtable
+
+
+                ; if the macsyma flag is set, change the syntax to the
+                ; maclisp standard syntax.  We must be careful that we
+                ; dont clobber any syntax changes made by files preloaded
+                ; into the compiler.
+
+                (cond (fl-macl (setsyntax '\/ 'vescape)        ;  143 = vesc
+
+                               (cond ((eq 'vescape (getsyntax '\\))
+                                      (setsyntax '\\ 'vcharacter)))
+
+                               (cond ((eq 'vleft-bracket (getsyntax '\[))
+                                      (setsyntax '\[ 'vcharacter)
+                                      (setsyntax '\] 'vcharacter)))
+                               (setq ibase  8.)
+                               (sstatus uctolc t)
+                               
+                               (d-makespec 'ibase)     ; to be special
+                               (d-makespec 'base)
+                               (d-makespec 'tty)
+
+                               (errset (cond ((null (getd 'macsyma-env))
+                                              (load 'machacks)))
+                                       nil))
+                      (fl-uci (load "ucifnc")
+                              (cvttoucilisp)))
+
+                (cond (fl-inter (putprop '* 'cc-ignore 'fl-exprcc) ;comment
+                                (remprop '* 'fl-expr)
+                                ))
+
+                (cond ((checkfatal) (return 1)))  ; leave if fatal errors      
+
+                (if fl-verb 
+                    then (comp-msg "Compilation begins with " compiler-name )
+                         (comp-msg "source: "  v-ifile ", result: "
+                                   (cond (fl-asm v-ofile) (t v-sfile))))
+
+                (setq piport vp-ifile)         ; set to standard input
+                (setq liszt-root-name v-root
+                      liszt-file-name v-ifile)
+
+
+                (if fl-run then (d-printautorun))
+       
+                (if fl-profile then (e-write1 '".globl mcount"))
+       loop
+
+               ; main loop of the compiler.  It reads a form and
+               ; compiles it. It continues to compile forms from
+               ; liszt-process-forms was long at that list is
+               ; non-empty.  This allows one form to spawn off other
+               ; forms to be compiled (an alternative to (progn 'compile))
+               ;
+               (cond ((atom (errset            ; list for debugging,
+                                               ; errset for production.
+                             (do ((i (read piport '<<end-of-file>>) 
+                                     (read piport '<<end-of-file>>))) 
+                                 ((eq i '<<end-of-file>>) nil)
+                                 (setq liszt-process-forms
+                                       (cons i liszt-process-forms))
+                                 (do ((this (car liszt-process-forms)
+                                            (car liszt-process-forms)))
+                                     ((null liszt-process-forms))
+                                     (unpush liszt-process-forms)
+                                     (catch (liszt-form this) Comp-error)))))
+                      (catch (comp-err "Lisp error during compilation")
+                             Comp-error)
+                      (setq piport nil)
+                      (setq er-fatal (1+ er-fatal))
+                      (return 1)))
+
+                (close piport)
+
+                ; if doing special character stuff (maclisp) reassert
+                ; the state
+
+                (cond (vps-include
+                       (comp-note  " done include")
+                       (setq piport (car vps-include)
+                             vps-include (cdr vps-include)
+                             v-ifile (car vns-include)
+                             vns-include (cdr vns-include))
+                       (go loop)))
+
+                (cond (liszt-eof-forms
+                       (do ((ll liszt-eof-forms (cdr ll)))
+                           ((null ll))
+                           (cond ((atom (errset (liszt-form (car ll))))
+                                  (catch
+                                   (comp-note "Lisp error during eof forms")
+                                   Comp-error)
+                                  (setq piport nil)
+                                  (return 1))))))
+
+                ; reset input base
+                (setq ibase 10.)
+                (setq readtable (makereadtable t))
+                (sstatus uctolc nil)   ; turn off case conversion
+                                       ; so bindtab will not have |'s
+                                       ; to quote lower case
+                (d-bindtab)
+
+                (d-printdocstuff)              ; describe this compiler
+
+                (cond ((portp vp-sfile)
+                       (close vp-sfile)))  ; close assembler language file
+
+                ; check for fatal errors and don't leave if so
+                (cond ((checkfatal) 
+                       (if fl-asm                      ; unlink .s file
+                           then (sys:unlink v-sfile))  ; if it is a tmp
+                       (return 1)))            ; and ret with error status
+
+                (comp-note "Compilation complete")
+
+                (setq tem (Divide (difference (sys:time) starttime) 60))
+                (setq ntem (ptime))
+
+                (setq temcp (Divide (difference (car ntem) (car startptime))
+                                   3600))
+
+                (setq temgc (Divide (difference (cadr ntem) (cadr startptime))
+                                   3600))
+
+                (comp-note " Time: Real: " (car tem) ":" (cadr tem)
+                       ", CPU: " (car temcp) ":" (quotient (cadr temcp) 60.0) 
+                        ", GC: " (car temgc) ":" (quotient (cadr temgc) 60.0) 
+                           " for "
+                           (difference $gccount$ startgccount)
+                           " gcs")
+
+                (cond (fl-xref
+                       (comp-note "Cross reference being generated")
+                       (print (list 'File v-ifile) vp-xfile)
+                       (terpr vp-xfile)
+                       (do ((ii g-allf (cdr ii)))
+                           ((null ii))
+                           (print (car ii) vp-xfile)
+                           (terpr vp-xfile))
+                       (close vp-xfile)))
+
+
+                ; the assember we use must generate the new a.out format
+                ; with a string table.  We will assume that the assembler
+                ; is in /usr/lib/lisp/as so that other sites can run
+                ; the new assembler without installing the new assembler
+                ; as /bin/as
+                (cond (fl-asm                  ; assemble file 
+                        (comp-note "Assembly begins")
+                        (cond ((not
+                                  (zerop
+                                     (setq asm-exit-status
+                                           (*process
+                                              (concat
+                                                 lisp-library-directory
+                                                 "/as "
+                                       #+for-vax "-V"   ; use virt mem
+                                                 " -o "
+                                                 v-ofile
+                                                 " "
+                                                 v-sfile)))))
+                               (comp-gerr "Assembler detected error, code: "
+                                          asm-exit-status)
+                               (comp-note "Assembler temp file " v-sfile
+                                          " is not unlinked"))
+                              (t (comp-note "Assembly completed successfully")
+                                 (errset (sys:unlink v-sfile)); unlink tmp
+                                                              ; file
+                                 (if fl-run
+                                     then (errset
+                                           (sys:chmod v-ofile #O775)))))))
+
+                #+(and sun (not unisoft))
+                (if (and v-ofile fl-run)
+                    then (if (null
+                              (errset (let ((port (fileopen v-ofile "r+")))
+                                           (fseek port 20 0)
+                                           (tyo 0 port)
+                                           (tyo 0 port)
+                                           (tyo 128 port)
+                                           (tyo 0 port)
+                                           (close port))))
+                             then (comp-err
+                                   "Error while fixing offset in object file: "
+                                   v-ofile)))
+
+                (setq readtable original-readtable)
+                #+monitoring
+                (errset (progn (monitor)       ; turn off monitoring
+                               (print 'monitor-off))
+                        nil)
+                (sstatus nofeature complr)
+                (return asm-exit-status))))
+
+(def checkfatal
+  (lambda nil
+         (cond ((greaterp er-fatal 0)
+                (catch (comp-err "Compilation aborted due to previous errors")
+                       Comp-error)
+                t))))
+
+;--- do-lisztrc-check
+; look for a liszt init file named
+;  .lisztrc  or  lisztrc or $HOME/.lisztrc or $HOME/lisztrc
+; followed by .o or .l or nothing
+; return the symbol 'error' if an error occured while reading.
+;
+(defun do-lisztrc-check nil
+   (do ((dirs `("." ,(getenv 'HOME)) (cdr dirs))
+       (val)
+       ($gcprint nil)
+       ($ldprint nil))
+       ((null dirs))
+       (if (setq val
+                (do ((name '(".lisztrc" "lisztrc") (cdr name))
+                     (val))
+                    ((null name))
+                    (if (setq val
+                              (do ((ext '(".o" ".l" "") (cdr ext))
+                                   (file))
+                                  ((null ext))
+                                  (if (probef
+                                         (setq file (concat (car dirs)
+                                                            "/"
+                                                            (car name)
+                                                            (car ext))))
+                                     then (if (atom (errset (load file)))
+                                             then (comp-msg
+                                       "Error loading liszt init file "
+                                                     file N
+                                                     "Compilation aborted" N)
+                                                  (return 'error)
+                                             else (return t)))))
+                       then (return val))))
+         then (return val))))
+
+      
+;--- liszt-form - i : form to compile
+;      This compiles one form.
+;
+(def liszt-form
+  (lambda (i)
+     (prog (tmp v-x)
+         ; macro expand
+       loop
+         (setq i (d-macroexpand i))
+         ; now look at what is left
+         (cond ((not (dtpr i)) (Push g-funcs `(eval ,i)))
+               ((eq (car i) 'def)
+                (cond (fl-verb (print (cadr i)) (terpr)(drain)))
+                (d-dodef i))
+               ((memq (car i) '(liszt-declare declare))
+                (funcall 'liszt-declare  (cdr i)))
+               ((eq (car i) 'eval-when) (doevalwhen i))
+               ((and (eq (car i) 'progn) (equal (cadr i) '(quote compile)))
+                ((lambda (internal-macros)     ; compile macros too
+                         (mapc 'liszt-form (cddr i)))
+                      t))
+               ((or (and (eq (car i) 'includef) (setq tmp (eval (cadr i))))
+                    (and (eq (car i) 'include ) (setq tmp (cadr i))))
+                (cond ((or (portp (setq v-x 
+                                        (car (errset (infile tmp) nil))))
+                           (portp (setq v-x 
+                                        (car
+                                           (errset
+                                              (infile
+                                                 (concat
+                                                    lisp-library-directory
+                                                    "/"
+                                                    tmp))
+                                              nil))))
+                           (portp (setq v-x 
+                                        (car (errset (infile (concat tmp
+                                                                     '".l")) 
+                                                     nil)))))
+                       (setq vps-include (cons piport vps-include))
+                       (setq piport v-x)
+                       (comp-note " INCLUDEing file: "  tmp)
+                       (setq vns-include (cons v-ifile vns-include)
+                             v-ifile tmp))
+                      (t (comp-gerr "Cannot open include file: " tmp))))
+               ((eq (car i) 'comment) nil)   ; just ignore comments
+               (t ; we have to macro expand
+                  ; certain forms we would normally
+                  ; just dump in the eval list.  This is due to hacks in
+                  ; the mit lisp compiler which are relied upon by certain
+                  ; code from mit.
+                  (setq i (d-fullmacroexpand i))
+                  
+                  (Push g-funcs `(eval ,i)))))))
+\f
+;--- d-dodef :: handle the def form
+;      - form : a def form: (def name (type args . body))
+;
+(defun d-dodef (form)
+  (prog (g-fname g-ftype g-args body lambdaform symlab g-arginfo
+                g-compfcn g-decls)
+
+     (setq g-arginfo 'empty)
+       
+ loop
+       ; extract the components of the def form
+       (setq g-fname (cadr form))
+       (if (dtpr (caddr form))
+           then (setq g-ftype (caaddr form)
+                      g-args (cadaddr form)
+                      body (cddaddr form)
+                      lambdaform (caddr form)
+                      symlab (gensym 'F))
+           else (comp-gerr "bad def form " form))
+       
+       ; check for a def which uses the mit hackish &xxx forms.
+       ; if seen, convert to a standard form and reexamine
+       ; the vax handles these forms in a special way.
+       #+for-68k
+       (if (or (memq '&rest g-args) 
+               (memq '&optional g-args)
+               (memq '&aux g-args))
+           then (setq form 
+                      `(def ,(cadr form) ,(lambdacvt (cdr lambdaform))))
+                (go loop))
+       
+       ; check for legal function name.  
+       ; then look at the type of the function and update the data base.
+       (if (null (atom g-fname))
+           then (comp-err "bad function name")
+           else (setq g-flocal (get g-fname g-localf))    ; check local decl.
+                ; macros are special, they are always evaluated
+                ; and sometimes compiled.
+                (if (and (not g-flocal) (eq g-ftype 'macro))
+                    then (eval form)
+                         (if (and (null macros)
+                                  (null internal-macros))
+                             then (comp-note g-fname
+                                             " macro will not be compiled")
+                                  (return nil))
+                         (Push g-funcs `(macro ,symlab ,g-fname))
+                         (if fl-anno then (setq g-arginfo nil)) ; no arg info
+                 elseif g-flocal
+                    then (if (null (or (eq g-ftype 'lambda)
+                                       (eq g-ftype 'nlambda)))
+                             then (comp-err
+                                      "bad type for local fcn: " g-ftype))
+                         (if (or (memq '&rest g-args)
+                                 (memq '&optional g-args)
+                                 (memq '&aux g-args))
+                             then (comp-err
+                                      "local functions can't use &keyword's "
+                                      g-fname))
+                 elseif (or (eq g-ftype 'lambda)
+                            (eq g-ftype 'lexpr))
+                    then (push `(lambda ,symlab ,g-fname) g-funcs)
+                         (putprop g-fname 'lambda g-functype)
+                 elseif (eq g-ftype 'nlambda)
+                    then (Push g-funcs `(nlambda ,symlab ,g-fname))
+                         (putprop g-fname 'nlambda g-functype)
+                    else (comp-err " bad function type " g-ftype)))
+       (setq g-skipcode nil)   ;make sure we aren't skipping code
+       (forcecomment `(fcn ,g-ftype ,g-fname))
+       (if g-flocal 
+          then (comp-note g-fname " is a local function")
+               (e-writel (car g-flocal))
+          else (if (null fl-vms) then (e-write2 '".globl" symlab))
+               (e-writel symlab))
+       (setq g-locs nil g-loccnt 0 g-labs nil g-loc 'reg g-cc nil
+             g-ret t g-topsym (d-genlab))
+       (if fl-xref then (setq g-refseen (gensym) g-reflst nil))
+       (d-clearreg)
+       #+for-68k (init-regmaskvec)
+       ; set up global variables which maintain knowledge about
+       ; the stack.  these variables are set up as if the correct
+       ; number of args were passed.
+       (setq g-compfcn t)      ; now compiling a function
+       (push nil g-labs)               ; no labels in a lambda
+       (setq g-currentargs (length g-args))
+       (d-prelude)                     ; do beginning stuff
+       
+       #+for-vax
+       (d-outerlambdacomp g-fname g-args (cddr lambdaform))
+       #+for-68k
+       (progn
+           (push (cons 'lambda 0) g-locs)
+           (mapc '(lambda (x)
+                      (push nil g-locs)
+                      (incr g-loccnt))
+                 g-args)
+           (d-lambbody lambdaform))
+
+       (d-fini)
+       (setq g-compfcn nil)            ; done compiling a fcn
+       (if fl-xref then 
+           (Push g-allf
+                 (cons g-fname
+                       (cons (cond (g-flocal (cons g-ftype 'local))
+                                   (t g-ftype))
+                             g-reflst))))
+       (if (and fl-anno (not (eq 'empty g-arginfo)))
+          then (Push g-funcs `(eval (putprop
+                                       ',g-fname
+                                       (list ',g-arginfo
+                                             ,g-complrname)
+                                       'fcn-info))))
+       ; by storing argument count information during compilation
+       ; we can arg number check calls to this function which occur
+       ; further on. 
+       (if (not (eq 'empty g-arginfo))
+          then (putprop g-fname (list g-arginfo) 'fcn-info))))
+
+;--- d-lambdalistcheck :: scan lambda var list for & forms
+; return
+;  (required optional rest op-p body)
+; required - list of required args
+; optional - list of (variable default [optional-p])
+; rest - either nil or the name of a variable for optionals
+; op-p - list of variables set to t or nil depending if optional exists
+; body - body to compile (has &aux's wrapped around it in lambdas)
+;
+#+for-vax
+(defun d-lambdalistcheck (list body)
+   (do ((xx list (cdr xx))
+       (state 'req)
+       (statechange)
+       (arg)
+       (req)(optional)(rest)(op-p)(aux))
+       ((null xx)
+       (list (nreverse req)
+             (nreverse optional)
+             rest
+             (nreverse op-p)
+             (d-lambda-aux-body-convert body (nreverse aux))))
+       (setq arg (car xx))
+       (if (memq arg '(&optional &rest &aux))
+         then (setq statechange arg)
+         else (setq statechange nil))
+       (caseq state
+             (req
+                (if statechange
+                   then (setq state statechange)
+                 elseif (and (symbolp arg) arg)
+                   then (push arg req)
+                   else (comp-err " illegal lambda variable " arg)))
+             (&optional
+                (if statechange
+                   then (if (memq statechange '(&rest &aux))
+                           then (setq state statechange)
+                           else (comp-err "illegal form in lambda list "
+                                          xx))
+                 elseif (symbolp arg)
+                   then ; optional which defaults to nil
+                        (push (list arg nil) optional)
+                 elseif (dtpr arg)
+                   then (if (and (symbolp (car arg))
+                                 (symbolp (caddr arg)))
+                           then ; optional with default
+                                (push arg optional)
+                                ; save op-p
+                                (if (cddr arg)
+                                   then (push (caddr arg) op-p)))
+                   else (comp-err "illegal &optional form "
+                                  arg)))
+             (&rest
+                (if statechange
+                   then (if (eq statechange '&aux)
+                           then (setq state statechange)
+                           else (comp-err "illegal lambda variable form "
+                                          xx))
+                 elseif rest
+                   then (comp-err
+                           "more than one rest variable in lambda list"
+                           arg)
+                   else (setq rest arg)))
+             (&aux
+                (if statechange
+                   then (comp-err "illegal lambda form " xx)
+                 elseif (and (symbolp arg) arg)
+                   then (push (list arg nil) aux)
+                 elseif (and (dtpr arg) (and (symbolp (car arg))
+                                             (car arg)))
+                   then (push arg aux)))
+             (t (comp-err "bizzarro internal compiler error ")))))
+
+;--- d-lambda-aux-body-convert :: convert aux's to lambdas
+; give a function body and a list of aux variables
+; and their inits, place a lambda initializing body around body
+; for each lambda (basically doing a let*).
+;
+#+for-vax
+(defun d-lambda-aux-body-convert (body auxlist)
+   (if (null auxlist)
+      then body
+      else `(((lambda (,(caar auxlist))
+               ,@(d-lambda-aux-body-convert body (cdr auxlist)))
+            ,(cadar auxlist)))))
+
+;--- d-outerlambdacomp :: compile a functions outer lambda body
+; This function compiles the lambda expression which defines
+; the function.   This lambda expression differs from the kind that
+; appears within a function because
+;  1. we aren't sure that the correct number of arguments have been stacked
+;  2. the keywords &optional, &rest, and &aux may appear
+;
+; funname - name of function
+; lambdalist - the local argument list, (with possible keywords)
+; body - what follows the lambdalist
+;
+; 
+;
+#+for-vax
+(defun d-outerlambdacomp (funname lambdalist body)
+   (let (((required optional rest op-p newbody)
+         (d-lambdalistcheck lambdalist body))
+        (g-decls g-decls)
+        (reqnum 0) maxwithopt labs (maxnum -1) args)
+       (d-scanfordecls body)
+       ; if this is a declared lexpr, we aren't called
+       ;
+       (if (and (null optional) (null rest))
+          then ; simple, the number of args is required
+               ; if lexpr or local function, then don't bother
+               (if (and (not g-flocal)
+                        (not (eq g-ftype 'lexpr)))
+                   then (d-checkforfixedargs
+                            funname
+                            (setq reqnum (setq maxnum (length required)))))
+          else ; complex, unknown number of args
+               ; cases:
+               ;  optional, no rest
+               ;  optional, with rest
+               ; no optional, rest + required
+               ; no optional, rest + no required
+               (setq reqnum (length required)
+                     maxwithopt (+ reqnum (length optional))
+                     maxnum (if rest then -1 else maxwithopt))
+               ; determine how many args were given
+               (e-sub3 '#.lbot-reg '#.np-reg '#.lbot-reg)
+               (e-write4 'ashl '$-2 '#.lbot-reg '#.lbot-reg)
+               ;
+               (if (null optional)
+                   then ; just a rest
+                        (let ((oklab (d-genlab))
+                              (lllab (d-genlab))
+                              (nopushlab (d-genlab)))
+                            (if (> reqnum 0)
+                                then (e-cmp '#.lbot-reg `($ ,reqnum))
+                                     (e-write2 'jgeq oklab)
+                                     ; not enough arguments given
+                                     (d-wnaerr funname reqnum -1)
+                                     (e-label oklab))
+                            (e-pushnil 1)
+                            (if (> reqnum 0)
+                                then (e-sub `($ ,reqnum) '#.lbot-reg)
+                                else (e-tst '#.lbot-reg))
+                            (e-write2 'jleq nopushlab)
+                            (e-label lllab)
+                            (e-quick-call '_qcons)
+                            (d-move 'reg 'stack)
+                            (e-write3 'sobgtr '#.lbot-reg lllab)
+                            (e-label nopushlab))
+                   else ; has optional args
+                        ; need one label for each optional plus 2
+                        (do ((xx optional (cdr xx))
+                             (res (list (d-genlab) (d-genlab))))
+                            ((null xx) (setq labs res))
+                            (push (d-genlab) res))
+                        ; push nils for missing optionals
+                        ; one case for required amount and one for
+                        ; each possible number of optionals
+                        (e-write4 'casel
+                                  '#.lbot-reg `($ ,reqnum)
+                                  `($ ,(- maxwithopt reqnum)))
+                        (e-label (car labs))
+                        (do ((xx (cdr labs) (cdr xx))
+                             (head (car labs)))
+                            ((null xx))
+                            (e-write2 '.word (concat (car xx) "-" head)))
+                        ; get here (when running code) if there are more
+                        ; than the optional number of args or if there are
+                        ; too few args.  If &rest is given, it is permitted
+                        ; to have more than the required number
+                        (let ((dorest (d-genlab))
+                              (again (d-genlab))
+                              (afterpush (d-genlab)))
+                            (if rest
+                                then ; check if there are greater than
+                                     ; the required number
+                                     ; preserve arg #
+                                     (C-push '#.lbot-reg)
+                                     (e-sub2 `($ ,maxwithopt) '#.lbot-reg)
+                                     (e-write2 'jgtr dorest)
+                                     (C-pop '#.lbot-reg))
+                            ; wrong number of args
+                            (d-wnaerr funname reqnum maxnum)
+                            (if rest
+                                then ; now cons the rest forms
+                                     (e-label dorest)
+                                     (e-pushnil 1)   ; list ends with nil
+                                     (e-label again)
+                                     (e-quick-call '_qcons)
+                                     (d-move 'reg 'stack)
+                                     ; and loop
+                                     (e-write3 'sobgtr '#.lbot-reg again)
+                                     ; arg #
+                                     (C-pop '#.lbot-reg)
+                                     (e-goto afterpush))
+                            ; push the nils on the optionals
+                            (do ((xx (cdr labs) (cdr xx)))
+                                ((null xx))
+                                (e-label (car xx))
+                                ; if we have exactly as many arguments given
+                                ; as the number of optionals, then we stack
+                                ; a nil if there is a &rest after
+                                ; the optionals
+                                (if (null (cdr xx))
+                                    then (if rest
+                                             then (e-pushnil 1))
+                                    else (e-pushnil 1)))
+                            (e-label afterpush))))
+       ; for optional-p's stack t's
+       (mapc '(lambda (form) (d-move 'T 'stack)) op-p)
+
+       ; now the variables must be shallow bound
+       ; creat a list of all arguments
+       (setq args (append required
+                         (mapcar 'car optional)
+                         (if rest then (list rest))
+                         op-p))
+
+       (push (cons 'lambda 0) g-locs)
+       (mapc '(lambda (x)
+                 (push nil g-locs))
+            args)
+       (setq g-loccnt (length args))
+       (d-bindlamb args)  ; do shallow binding if necessary
+       ;
+       ; if any of the optionals have non null defaults or
+       ; optional-p's, we have to evaluate their defaults
+       ; or set their predicates.
+       ; first, see if it is necessary
+       (if (do ((xx optional (cdr xx)))
+              ((null xx) nil)
+              (if (or (cadar xx)  ; if non null default
+                      (caddar xx)); or predicate
+                  then (return t)))
+          then (makecomment '(do optional defaults and preds))
+               ; create labels again
+               ; need one label for each optional plus 1
+               (do ((xx optional (cdr xx))
+                    (res (list (d-genlab) )))
+                   ((null xx) (setq labs res))
+                   (push (d-genlab) res))
+               ; we need to do something if the argument count
+               ; is between the number of required arguments and
+               ; the maximum number of args with optional minus 1.
+               ; we have one case for the required number and
+               ; one for each optional except the last optional number
+               ;
+               (let ((afterthis (d-genlab)))
+                   (e-write4 'casel
+                             '#.lbot-reg `($ ,reqnum)
+                             `($ ,(- maxwithopt reqnum 1)))
+                   (e-label (car labs))
+                   (do ((xx (cdr labs) (cdr xx))
+                        (head (car labs)))
+                       ((null xx))
+                       (e-write2 '.word (concat (car xx) "-" head)))
+                   (e-goto afterthis)
+                   (do ((ll (cdr labs) (cdr ll))
+                        (op optional (cdr op))
+                        (g-loc nil)
+                        (g-cc nil)
+                        (g-ret nil))
+                       ((null ll))
+                       (e-label (car ll))
+                       (if (caddar op)
+                           then (d-exp `(setq ,(caddar op) nil)))
+                       (if (cadar op)
+                           then (d-exp `(setq ,(caar op) ,(cadar op)))))
+                   (e-label afterthis)))
+
+       ; now compile the function
+       (d-clearreg)
+       (setq g-arginfo
+            (if (eq g-ftype 'nlambda)
+                then nil
+                else (cons reqnum (if (>& maxnum 0) then maxnum else nil))))
+       (makecomment '(begin-fcn-body))
+       (d-exp (do ((ll newbody (cdr ll))
+                  (g-loc)
+                  (g-cc)
+                  (g-ret))
+                 ((null (cdr ll)) (car ll))
+                 (d-exp (car ll))))
+       (d-unbind)))
+
+#+for-vax
+(defun d-checkforfixedargs (fcnname number)
+   (let ((oklab (d-genlab)))
+      (makecomment `(,fcnname should-have-exactly ,number args))
+      ; calc -4*# of args
+      (e-sub '#.np-reg '#.lbot-reg)
+      (e-cmp '#.lbot-reg `($ ,(- (* number 4))))
+      (e-write2 'jeql oklab)
+      (d-wnaerr fcnname number number)
+      (e-label oklab)))
+
+;--- d-wnaerr  :: generate code to call wrong number of args error
+; name is the function name,
+; min is the minumum number of args for this function
+; max is the maximum number (-1 if there is no maximum)
+;  we encode the min and max in the way shown below.
+;
+#+for-vax
+(defun d-wnaerr (name min max)
+   (makecomment `(arg error for fcn ,name min ,min max ,max))
+   (e-move 'r10 '#.lbot-reg)
+   (C-push `($ ,(+ (* min 1000) (+ max 1))))
+   (C-push (e-cvt (d-loclit name nil)))
+   (e-write3 'calls '$2 '_wnaerr))
+
+;--- d-genlab :: generate a pseudo label
+;
+(defun d-genlab nil
+  (gensym 'L))
+
+;--- liszt-interrupt-signal
+; if we receive a interrupt signal (commonly a ^C), then
+; unlink the .s file if we are generating a temporary one
+; and exit
+(defun liszt-interrupt-signal (sig)
+   (if (and fl-asm (boundp 'v-sfile) v-sfile)
+      then (sys:unlink v-sfile))
+   (exit 1))
diff --git a/usr/src/ucb/lisp/liszt/util.l b/usr/src/ucb/lisp/liszt/util.l
new file mode 100644 (file)
index 0000000..0f73eb6
--- /dev/null
@@ -0,0 +1,406 @@
+(include-if (null (get 'chead 'version)) "../chead.l")
+(Liszt-file util
+   "$Header: util.l,v 1.14 83/08/28 17:13:11 layer Exp $")
+
+;;; ----       u t i l                 general utility functions
+;;;
+;;;                            -[Tue Aug 16 17:17:32 1983 by layer]-
+
+
+;--- d-handlecc :: handle g-cc
+; at this point the Z condition code has been set up and if g-cc is
+; non nil, we must jump on condition to the label given in g-cc
+;
+(defun d-handlecc nil
+   (if (car g-cc)
+       then (e-gotot (car g-cc))
+    elseif (cdr g-cc)
+       then (e-gotonil (cdr g-cc))))
+
+;--- d-invert :: handle inverted condition codes
+; this routine is called if a result has just be computed which alters
+; the condition codes such that Z=1 if the result is t, and Z=0 if the
+; result is nil (this is the reverse of the usual sense).  The purpose
+; of this routine is to handle g-cc and g-loc.  That is if g-loc is 
+; specified, we must convert the value of the Z bit of the condition 
+; code to t or nil and store that in g-loc.  After handling g-loc we
+; must handle g-cc, that is if the part of g-cc is non nil which matches
+; the inverse of the current condition code, we must jump to that.
+;
+(defun d-invert nil
+  (if (null g-loc) 
+      then (if (car g-cc) then (e-gotonil (car g-cc))
+           elseif (cdr g-cc) then  (e-gotot (cdr g-cc)))
+      else (let ((lab1 (d-genlab))
+                (lab2 (if (cdr g-cc) thenret else (d-genlab))))
+               (e-gotonil lab1)
+               ; Z=1, but remember that this implies nil due to inversion
+               (d-move 'Nil g-loc)
+               (e-goto lab2)
+               (e-label lab1)
+               ; Z=0, which means t
+               (d-move 'T g-loc)
+               (if (car g-cc) then (e-goto (car g-cc)))
+               (if (null (cdr g-cc)) then (e-label lab2)))))
+                       
+;--- d-noninvert :: handle g-cc and g-loc assuming cc non inverted
+; 
+; like d-invert except Z=0 implies nil, and Z=1 implies t
+;
+(defun d-noninvert nil
+  (if (null g-loc) 
+      then (if (car g-cc) then (e-gotot (car g-cc))
+           elseif (cdr g-cc) then  (e-gotonil (cdr g-cc)))
+      else (let ((lab1 (d-genlab))
+                (lab2 (if (cdr g-cc) thenret else (d-genlab))))
+               (e-gotot lab1)
+               ; Z=0, this implies nil
+               (d-move 'Nil g-loc)
+               (e-goto lab2)
+               (e-label lab1)
+               ; Z=1, which means t
+               (d-move 'T g-loc)
+               (if (car g-cc) then (e-goto (car g-cc)))
+               (if (null (cdr g-cc)) then (e-label lab2)))))
+
+;--- d-macroexpand :: macro expand a form as much as possible
+;
+; only macro expands the top level though.
+(defun d-macroexpand (i)
+   (prog (first type)
+      loop
+      (if (and (dtpr i) (symbolp (setq first (car i))))
+        then (if (eq 'macro (setq type (d-functyp first 'macro-ok)))
+                then (setq i (apply first i))
+                     (go loop)
+              elseif (eq 'cmacro type)
+                then (setq i (apply (get first 'cmacro) i))
+                     (go loop)))
+      (return i)))
+
+;--- d-fullmacroexpand :: macro expand down all levels
+; this is not always possible to due since it is not always clear
+; if a function is a lambda or nlambda, and there are lots of special
+; forms.  This is just a first shot at such a function, this should
+; be improved upon.
+;
+(defun d-fullmacroexpand (form)
+   (if (not (dtpr form))
+       then form
+       else (setq form (d-macroexpand form))   ; do one level
+            (if (and (dtpr form) (symbolp (car form)))
+               then (let ((func (getd (car form))))
+                         (if (or (and (bcdp func)
+                                      (eq 'lambda (getdisc func)))
+                                 (and (dtpr func)
+                                      (memq (car func) '(lambda lexpr)))
+                                 (memq (car form) '(or and)))
+                             then `(,(car form)
+                                     ,@(mapcar 'd-fullmacroexpand
+                                               (cdr form)))
+                           elseif (eq (car form) 'setq)
+                             then (d-setqexpand form)
+                           else form))
+               else form)))
+
+;--- d-setqexpand :: macro expand a setq statemant
+; a setq is unusual in that alternate values are macroexpanded.
+;
+(defun d-setqexpand (form)
+   (if (oddp (length (cdr form)))
+       then (comp-err "wrong number of args to setq " form)
+       else (do ((xx (reverse (cdr form)) (cddr xx))
+                (res))
+               ((null xx) (cons 'setq res))
+               (setq res `(,(cadr xx)
+                            ,(d-fullmacroexpand (car xx))
+                            ,@res)))))
+   
+;--- d-typesimp ::  determine the type of the argument 
+;
+#+for-vax
+(defun d-typesimp (arg val)
+  (let ((argloc (d-simple arg)))
+       (if (null argloc)
+           then (let ((g-loc 'reg)
+                      g-cc g-ret)
+                    (d-exp arg))
+                (setq argloc 'reg))
+       (e-write4 'ashl '$-9 (e-cvt argloc) 'r0)
+       (e-write3 'cmpb '"_typetable+1[r0]" val)
+       (d-invert)))
+
+#+for-68k
+(defun d-typesimp (arg val)
+   (let ((argloc (d-simple arg)))
+       (if (null argloc)
+          then (let ((g-loc 'reg)
+                     g-cc g-ret)
+                   (d-exp arg))
+               (setq argloc 'reg)
+          else (e-move (e-cvt argloc) 'd0))
+       (e-sub '#.nil-reg 'd0)
+       (e-write3 'moveq '($ 9) 'd1)
+       (e-write3 'asrl 'd1 'd0)
+       (e-write3 'lea '"_typetable+1" 'a5)
+       (e-write3 'cmpb val '(% 0 a5 d0))
+       (d-invert)))
+
+;--- d-typecmplx  :: determine if arg has one of many types
+;      - arg : lcode argument to be evaluated and checked
+;      - vals : fixnum with a bit in position n if we are to check type n
+;
+#+for-vax
+(defun d-typecmplx (arg vals)
+  (let ((argloc (d-simple arg))
+       (reg))
+       (if (null argloc) then (let ((g-loc 'reg)
+                                   g-cc g-ret)
+                                  (d-exp arg))
+                             (setq argloc 'reg))
+       (setq reg 'r0)
+       (e-write4 'ashl '$-9 (e-cvt argloc) reg)
+       (e-write3 'cvtbl (concat "_typetable+1[" reg "]") reg)
+       (e-write4 'ashl reg '$1 reg)
+       (e-write3 'bitw vals reg)
+       (d-noninvert)))
+
+#+for-68k
+(defun d-typecmplx (arg vals)
+   (let ((argloc (d-simple arg))
+        (l1 (d-genlab))
+        (l2 (d-genlab)))
+       (makecomment '(d-typecmplx: type check))
+       (if (null argloc)
+          then (let ((g-loc 'reg)
+                     g-cc g-ret)
+                   (d-exp arg))
+               (setq argloc 'reg)
+          else (e-move (e-cvt argloc) 'd0))
+       (e-sub '#.nil-reg 'd0)
+       (e-write3 'moveq '($ 9) 'd1)
+       (e-write3 'asrl 'd1 'd0)
+       (e-write3 'lea '"_typetable+1" 'a5)
+       (e-add 'd0 'a5)
+       (e-write3 'movb '(0 a5) 'd0)
+       (e-write2 'extw 'd0)
+       (e-write2 'extl 'd0)
+       (e-write3 'moveq '($ 1) 'd1)
+       (e-write3 'asll 'd0 'd1)
+       (e-move 'd1 'd0)
+       (e-write3 'andw vals 'd0)
+       (d-noninvert)
+       (makecomment '(d-typecmplx: end))))
+
+;---- register handling routines.
+
+;--- d-allocreg :: allocate a register 
+;  name - the name of the register to allocate or nil if we should
+;        allocate the least recently used.
+;
+(defun d-allocreg (name)
+  (if name 
+      then (let ((av (assoc name g-reguse)))
+               (if av then (rplaca (cdr av) (1+ (cadr av)))) ; inc used count
+               name)
+      else ; find smallest used count
+          (do ((small (car g-reguse))
+               (smc (cadar g-reguse))
+               (lis (cdr g-reguse) (cdr lis)))
+              ((null lis)
+               (rplaca (cdr small) (1+ smc))
+               (car small))
+              (if (< (cadar lis) smc)
+                  then (setq small (car lis)
+                             smc   (cadr small))))))
+
+
+;--- d-bestreg :: determine the register which is closest to what we have
+;  name - name of variable whose subcontents we want
+;  pat  - list of d's and a's which tell which part we want
+;
+(defun d-bestreg (name pat)
+  (do ((ll g-reguse (cdr ll))
+       (val)
+       (best)
+       (tmp)
+       (bestv -1))
+      ((null ll)
+       (if best
+          then (rplaca (cdr best) (1+ (cadr best)))
+               (list (car best)
+                     (if (> bestv 0) 
+                         then (rplacd (nthcdr (1- bestv)
+                                              (setq tmp
+                                                    (copy pat)))
+                                      nil)
+                              tmp
+                         else nil)
+                     (nthcdr bestv pat))))
+      (if (and (setq val (cddar ll))
+              (eq name (car val)))
+         then (if (> (setq tmp (d-matchcnt pat (cdr val)))
+                     bestv)
+                  then (setq bestv tmp
+                             best  (car ll))))))
+
+;--- d-matchcnt :: determine how many parts of a pattern match
+; want - pattern we want to achieve
+; have - pattern whose value exists in a register
+; 
+; we return a count of the number of parts of the pattern match.
+; If this pattern will be any help at all, we return a value from 
+; 0 to the length of the pattern.
+; If this pattern will not work at all, we return a number smaller
+; than -1.  
+; For `have' to be useful for `want', `have' must be a substring of 
+; `want'.  If it is a substring, we return the length of `have'.
+; 
+(defun d-matchcnt (want have)
+  (let ((length 0))
+       (if (do ((hh have (cdr hh))
+               (ww want (cdr ww)))
+              ((null hh) t)
+              (if (or (null ww) (not (eq (car ww) (car hh))))
+                  then (return nil)
+                  else (incr length)))
+          then  length
+          else  -2)))
+
+;--- d-clearreg :: clear all values in registers or just one
+; if no args are given, clear all registers.
+; if an arg is given, clear that register
+;
+(defun d-clearreg n
+  (cond ((zerop n) 
+        (mapc '(lambda (x) (rplaca (cdr x) 0)
+                    (rplacd (cdr x) nil))
+              g-reguse))
+       (t (let ((av (assoc (arg 1) g-reguse)))
+               (if av
+                  then
+                       #+for-68k (d-regused (car av))
+                       (rplaca (cdr av) 0)
+                       (rplacd (cdr av) nil)
+                  else nil)))))
+
+;--- d-clearuse :: clear all register which reference a given variable
+;
+(defun d-clearuse (varib)
+  (mapc '(lambda (x)
+                (if (eq (caddr x) varib) then (rplacd (cdr x) nil)))
+       g-reguse))
+
+;--- d-inreg :: declare that a value is in a register
+; name - register name
+; value - value in a register
+;
+(defun d-inreg (name value)
+  (let ((av (assoc name g-reguse)))
+       (if av then (rplacd (cdr av) value))
+       name))
+
+(defun e-setup-np-lbot nil
+   (e-move '#.np-reg '#.np-sym)
+   (e-move '#.lbot-reg '#.lbot-sym))
+
+;---------------MC68000 only routines
+#+for-68k
+(progn 'compile
+
+;--- d-regtype :: find out what type of register the operand goes
+;                in.
+; eiadr - an EIADR
+;
+(defun d-regtype (eiadr)
+   (if (symbolp eiadr)
+       then (if (memq eiadr '(d0 d1 d2 d3 d4 d5 d6 d7 reg)) then 'd
+            elseif (memq eiadr '(a0 a1 a2 a3 a4 a5 a6 a7 sp areg)) then 'a)
+    elseif (or (eq '\# (car eiadr))
+              (eq '$ (car eiadr))
+              (and (eq '* (car eiadr))
+                   (eq '\# (cadr eiadr))))
+       then 'd
+       else 'a))
+
+;--- d-regused :: declare that a reg is used in a function
+;      regname - name of the register that is going to be used
+;                (ie, 'd0 'a2...)
+;
+(defun d-regused (regname)
+   (let ((regnum (diff (cadr (exploden regname)) 48))
+        (regtype (car (explode regname))))
+       (if (memq regname '(a0 a1 d0 d1))
+          thenret
+       elseif (equal 'd regtype)
+          then (rplacx regnum g-regmaskvec t) regname
+          else (rplacx (plus regnum 8) g-regmaskvec t) regname)))
+
+;--- d-makemask :: make register mask for moveml instr
+;
+(defun d-makemask ()
+   (do ((ii 0 (1+ ii))
+       (mask 0))
+       ((greaterp ii 15) mask)
+       (if (cxr ii g-regmaskvec)
+          then (setq mask (plus mask (expt 2 ii))))))
+
+;--- init-regmaskvec :: initalize hunk structure to all default
+;                      save mask.
+;
+; nil means don't save it, and t means save the register upon function entry.
+; order in vector: d0 .. d7, a0 .. a7.
+; d3 : lbot (if $global-reg$ is t then save)
+; d7 : _nilatom
+; a2 : _np
+; a3 : literal table ptr
+; a4 : old _lbot (if $global-reg$ is t don't save)
+; a5 : intermediate address calc
+;
+(defun init-regmaskvec ()
+   (setq g-regmaskvec
+        (makhunk
+            (if $global-reg$
+                then (quote (nil nil nil t   nil nil nil t
+                             nil nil t   t   t   t   nil nil))
+                else (quote (nil nil nil nil nil nil nil t
+                             nil nil t   t   t   t   nil nil))))))
+
+;--- Cstackspace :: calc local space on C stack
+; space = 4 * (no. of register variables saved on stack)
+;
+(defun Cstackspace ()
+   (do ((ii 0 (1+ ii))
+       (retval 0))
+       ((greaterp ii 15) (* 4 retval))
+       (if (cxr ii g-regmaskvec) then (setq retval (1+ retval)))))
+
+;--- d-alloc-register :: allocate a register
+;  type - type of register (a or d)
+;  name - the name of the register to allocate or nil if we should
+;        allocate the least recently used.
+;
+(defun d-alloc-register (type name)
+   (if name 
+       then (let ((av (assoc name g-reguse)))
+               (d-regused name)
+               (if av then (rplaca (cdr av) (1+ (cadr av)))) ; inc used count
+               name)
+       else ; find smallest used count
+           (let ((reguse))
+               (do ((cur g-reguse (cdr cur)))
+                   ((null cur))
+                   (if (eq type (car (explode (caar cur))))
+                       then (setq reguse (cons (car cur) reguse))))
+               (do ((small (car reguse))
+                    (smc (cadar reguse))
+                    (lis (cdr reguse) (cdr lis)))
+                   ((null lis)
+                    (rplaca (cdr small) (1+ smc))
+                    (d-regused (car small))
+                    (car small))
+                   (if (< (cadar lis) smc)
+                       then (setq small (car lis)
+                                  smc   (cadr small)))))))
+
+); end 68000 only routines
diff --git a/usr/src/ucb/lisp/liszt/vax/Makefile b/usr/src/ucb/lisp/liszt/vax/Makefile
new file mode 100644 (file)
index 0000000..e7d5c0b
--- /dev/null
@@ -0,0 +1,123 @@
+#$Header: /na/franz/liszt/vax/RCS/Makefile,v 1.6 83/08/15 19:27:49 layer Exp $
+#
+#      Makefile for liszt 
+#
+# Copyright (c) 1980, 1982, The Regents of the University of California.
+# the Copyright applies to all files referenced in this Makefile.
+# All rights reserved.  
+# author: j. foderaro
+#
+# this makefile creates these things:
+#   nliszt - the lisp compiler.  We call it nliszt so we can test it out
+#           without having to say ./liszt
+#   tags - a tags file for use by ex/vi
+#
+# CTE refers to compile time enviroment 
+#
+#--- Default Paths and programs
+#
+.DEFAULT:nliszt
+
+CopyTo = /dev/null
+ObjDir = /usr/ucb
+Liszt = ${ObjDir}/liszt
+Lisp = ${ObjDir}/lisp
+
+Flg = -xqa
+
+CTESrc = ../chead.l ../cmacros.l ../const.l
+
+CTEObj= cmacros.o
+
+Src =  ../array.l ../datab.l ../decl.l         ../expr.l ../fixnum.l ../funa.l  \
+       ../funb.l ../func.l ../io.l ../tlev.l ../util.l ../lversion.l   \
+       ../vector.l ../instr.l
+
+SharedSrc = ${CTESrc} ${Src} ../ChangeLog ../cmake.l
+
+AllSrc =  Makefile lisprc.l lisztrc.l
+
+Obj = array.o datab.o decl.o expr.o fixnum.o funa.o funb.o func.o io.o \
+       tlev.o util.o lversion.o vector.o instr.o
+
+AllObj =  ${CTEObj} ${Obj}
+
+donliszt:
+       rm -f nliszt
+       make Liszt=${Liszt} Lisp=${Lisp} nliszt
+
+nliszt: ${CTEObj} ${Obj} ${Lisp}
+       echo "(load '../cmake.l)(genl nliszt)" | ${Lisp} 
+
+#--- generate an interpreted version
+snliszt: ${Src} ${Lisp}
+       echo "(load '../cmake.l)(genl snliszt slow)" | ${Lisp}
+
+array.o: ../array.l
+       ${Liszt} ${Flg} ../array.l -o array.o
+
+vector.o: ../vector.l
+       ${Liszt} ${Flg} ../vector.l -o vector.o
+
+instr.o: ../instr.l
+       ${Liszt} ${Flg} ../instr.l -o instr.o
+
+datab.o: ../datab.l
+       ${Liszt} ${Flg} ../datab.l -o datab.o
+
+decl.o: ../decl.l
+       ${Liszt} ${Flg} ../decl.l -o decl.o
+
+expr.o: ../expr.l
+       ${Liszt} ${Flg} ../expr.l -o expr.o
+
+fixnum.o: ../fixnum.l
+       ${Liszt} ${Flg} ../fixnum.l -o fixnum.o
+
+funa.o: ../funa.l
+       ${Liszt} ${Flg} ../funa.l -o funa.o
+
+funb.o: ../funb.l
+       ${Liszt} ${Flg} ../funb.l -o funb.o
+
+func.o: ../func.l
+       ${Liszt} ${Flg} ../func.l -o func.o
+
+io.o: ../io.l
+       ${Liszt} ${Flg} ../io.l -o io.o
+
+tlev.o: ../tlev.l
+       ${Liszt} ${Flg} ../tlev.l -o tlev.o
+
+util.o: ../util.l
+       ${Liszt} ${Flg} ../util.l -o util.o
+
+lversion.o: ../lversion.l
+       ${Liszt} ${Flg} ../lversion.l -o lversion.o
+
+cmacros.o: ../cmacros.l
+       ${Liszt} ${Flg} ../cmacros.l -o cmacros.o
+
+tags:  ../tags ${Src} ${CTESrc}
+       awk -f ../ltags ${Src} ${CTESrc} | sort > ../tags
+
+#
+install: nliszt
+       -rm -f ${ObjDir}/liszt
+       mv nliszt ${ObjDir}/liszt
+
+copysource: ${AllSrc}
+       (tar cf - ${AllSrc} | (cd ${CopyTo} ; tar xf -))
+
+copyobjects: ${AllObj}
+       (tar cf - ${AllObj} | (cd ${CopyTo} ; tar xf -))
+
+scriptcatall: ${AllSrc}
+       @../../scriptcat . liszt/vax ${AllSrc}
+
+cleanobj:      
+       rm -f \#* *.[xo] map
+
+clean:
+       make cleanobj
+       rm -f nliszt snliszt
diff --git a/usr/src/ucb/lisp/pearl/ChangeLog b/usr/src/ucb/lisp/pearl/ChangeLog
new file mode 100644 (file)
index 0000000..3e98520
--- /dev/null
@@ -0,0 +1,403 @@
+    Changes to PEARL since the User's Manual.
+
+6/26/83 -- Version 3.9: Misc. bug fixes -- distributed with 4.2.
+-- Fixed a(n embarassingly) large number of bugs in the functions
+relating to blocks and freezing and thawing variables.  User visible
+changes are that freezeblock and thawblock are now fexprs expecting
+the name of the block to be frozen.  Blocks without names cannot be
+frozen or thawed individually.  A prominent bug was also found in
+freezebindings which did not work correctly when the structure being
+frozen had no non-frozen variables of its own.
+
+6/21/83
+-- Changed the name of the "selectq" in ucisubset.l to "selectq*" to
+avoid the new Franz function "selectq" which requires the default case
+to be labeled with "t" or "otherwise".  Changed all PEARL code to use
+the new Franz selectq.
+
+5/14/83 -- Version 3.8: Unification added.
+-- Added unification pattern matching as an option, using code written
+by Dave Chin.  To turn on unification, call the function "useunification".
+There is currently no way to turn it off since the code as written
+cannot handle old unification results if it doesn't think unification
+is taking place (controlled by special variable *unifyunbounds*).
+It is not as expensive as expected so this may be changed.
+-- Also fixed serious bugs in "setv".
+
+5/12/83
+-- Fixed bug in create which caused the mechanism of changing the type
+of create being done in nested structures to fail.
+
+5/6/83
+-- Fixed bug in printing of global adjunct variables.
+
+5/1/83
+-- Fixed various major bugs in varreplace.
+
+4/26/83 -- Version 3.7: Two part compilation and minor bug fixes
+           in scopy and hooks.
+-- Created a way to do a "make" which compiles in two pieces for small
+machines.  Simply define "make pearl" as either "big" or "small"
+depending on memory size (Less than about 2.5 Mb of memory requires
+"small").
+-- Changed "scopy" and related functions so that the abbreviation on the
+copy is just gensym'ed from the old abbreviation, without adding ":copy".
+-- Fixed a bug in the hook functions which caused all slots after the ones
+with hooks to execute the result (*done*, etc) of the first one.
+
+3/28/83 -- Version 3.6: Inherit all slot hooks and predicates and unbind
+           incorrectly bound global variables after failed match.
+--- Slot hooks are now always inherited and added to, rather than
+replaced.  If the hooks and predicates of a slot are preceded by "instead"
+then inheriting doesn't happen and hooks and predicates are replaced.
+--- Fixed match so that if an unbound global variable is set during a match
+that later fails, the value is restored to *pearlunbound*.  The names of
+variables that are set are saved in the special variable *globalsavestack*.
+
+3/18/83 -- Version 3.5: New print functions.
+--- Rewrote all the print functions.  Externally, the three old
+pairs of functions: "valprint"/"valform", "fullprint"/"fullform",
+and "abbrevprint"/"abbrevform" behave the same.  However, there is now
+a function called "allform" which all of these use which adjusts its
+treatment of a structure based on several special atoms:
+    1. *abbrevprint* -- non-nil value causes abbreviations to be used
+whenever possible.  "abbrevform" (and thus "abbrevprint") lambda-binds
+this to t and calls "allform".  "fullform" binds this to nil.
+    2. *fullprint* -- non-nil value causes complete information
+including hooks and predicates to be given when present.  "fullform"
+(and thus "fullprint") lambda-binds this to t and calls "allform".
+"abbrevform" binds this to nil.
+    3. *uniqueprint* -- described below.
+    4. *quiet* -- described below.
+"valform" lambda-binds both to nil which is their default values.
+Thus, the default action of "allform" used by itself will be like "valform".
+--- All the default print functions which used to use "valprint"
+automatically now use "allprint" so that they can all be changed by
+changes to the default values of *abbrevprint* and *fullprint*.
+--- The third atom which affects the behavior of all the print functions
+is *uniqueprint*.  If it is given a non-nil value then if a structure
+is encountered more than once during the same top-level call to a
+print function, it will be translated into exactly the same cons-cells.
+This saves on cons-cells and also makes it possible for the "*form"
+functions to handle circular structures, although "sprint" and thus
+the "*print" functions can't handle the result.  Since most people
+seldom have duplications within a structure, the default is OFF (nil).
+The assoc list is stored in the special atom *uniqueprintlist*.
+--- "form" and "print" functions were added to handle structures,
+streams and symbols specially.  They are called
+"structureform", "structureprint" "symbolform", "symbolprint",
+"streamform" and "streamprint" and do not ensure that you give them
+the right type of value.
+--- The fourth atom which affects the behavior of all the print
+functions is *quiet* which, if non-nil, keeps them from running
+either sprint or the *form function.   This is helpful for when you
+wish to turn off ALL printing in one fell swoop.  A function called
+"quiet" was also added which behaves like progn, except that it
+lambda-binds *quiet* to t during the evaluation of its arguments,
+provided a local island of "quiet".
+
+3/8/83 -- Version 3.4: Type tags added.
+--- Added a field to definitions, structures, symbols, and databases to
+indicate what they were to speed up type checking.  All relevant
+functions related to structures and databases were changed.
+--- Fixed some bugs in releasedb.
+--- Many lowlevel functions in PEARL were changed, but none in ways that would
+affect most people (because they shouldn't be using the changed functions).
+
+3/4/83 -- Version 3.3: New faster hashing.
+--- Changed internal code to do the hashing so that it only gets the value
+out of a slot once instead of as many as 4 times as before.  Resulted
+in about a 5% speedup for structures only hashed a couple of ways.
+Should be more for multiply hashed items.  Should also make new
+hashing methods easier to add.
+
+2/25/83 -- Version 3.2: Slot encoding applied to speeded-up match.
+--- Rewrote match functions to use the new slot encoding.  Provided
+about a 10% speedup.
+--- There are now two different kinds of match function: "standardmatch"
+and "basicmatch" will only match two structures of the same type.
+"standardexpandedmatch" and "basicexpandedmatch" will match two
+structures which are related hierarchically (one above the other)
+on the slots they have in common.  "standardfetch" uses the regular
+versions and "expandedfetch" uses the expanded versions.
+
+2/21/83
+--- Changed all special variables in PEARL to be defined with defvar so
+that fasl'ing in pearl.o at compile time will automatically declare them
+special again.
+
+2/17/83 -- Version 3.1: Slot encoding for speed.
+--- Added major and minor version numbers to PEARL, stored in
+"pearlmajorversion" and "pearlminorversion" respectively.
+Started at 3.1 for this version.
+--- Added new method of storing in slots to speed up some things.
+--- Putpath, delsetpath, addsetpath and clearpath now will work on a
+slot with any kind of value or variable in it but result in a constant
+value.  This may cause problems, and if it does it will be "fixed" to
+worry about what was there and decide what to do to it.
+--- Scopy no longer throws away bound adjunct variables.
+--- Many functions listed in the manual as being "proprietary" to PEARL
+(i.e., not safe to use) have gone away.  There are too many to list here.
+
+1/23/83
+--- Fixed a bug which made slots inherit hashing when redescribed in an
+expanded structure unless new hashing was specifically included.
+--- Added a new "hashing mark" "+", for redescribed slots of expanded
+structures only, which says copy the old info and add the following
+new hashing too.  It must come first to be effective.
+    Thus, the following should work:
+       (cb x (* a int))
+       (ce x y (a ^))
+       (ce x z (+ : a ^))
+       (ce x w (: + a ^)) ;; anomalous use of +
+resulting in:
+       * hashing in x,
+       no hashing in y,
+       both * and : hashing in z,
+    and only * hashing in w (because of misplacement of +).
+
+1/19/83
+--- Merged the file sprint.l into ucisubset.l.
+
+1/18/83
+--- Miscellaneous changes to functions length and others in ucisubset.l
+to improve efficiency.
+
+1/7/83
+--- Changed ,@ to ., in most cases (i.e., whenever equivalent) to
+avoid an unneeded append generated by the backquote macro.
+
+12/24/82
+--- Made change in the definitions of de, df, dm, drm and dsm so that
+if the special variable *savedefs* is nil then old definitions of functions
+are not saved.  This is especially useful in compiling (and hence assembly
+and loading) since it will speed it up quite a bit.  The saving of the file
+the definition was in is also disabled.  The variable *savedefs* is
+normally t which causes these macros to act as before, saving the
+definition, etc.  If *savedefs* is nil, then they simply expand into the
+appropriate defun or setsyntax.  The following lines should be
+included in the file to have this effect only at compile time:
+    (eval-when (compile)
+              (declare (special *savedefs*))
+              (setq *savedefs* nil))
+If you want to permanently disable the saving in your lisp,
+simply put a
+    (setq *savedefs* nil)
+in your .lisprc file AFTER the loading of ucisubset.l.
+
+11/12/82
+--- Removed association of "remove" with Franz's "delete" so that
+Franz's remove could be used and fixed all references to "remove" and
+"dremove", changing many to "delq"s.
+--- Deleted "powercopy" and redefinition of "copy" now that Franz has
+correct meaning (doesn't attempt to copy hunks) for copy.
+
+10/30/82
+--- All the exprs whose names were of the form XXXX1 where XXXX was the
+name of a lexpr which was a principle function of PEARL were eliminated
+(i.e., absorbed by the other form).
+--- Many small changes to speed up PEARL, including:
+    1. Changed many progs to lets.
+    2. Inserted progn's around (or (non-error)
+                                  (not (msg t .....))
+                                  (pearlbreak))
+    thus eliminating the not and clarifying the meaning.
+    3. Changed many pops to (setq x (cdr x)) (where popped item not wanted).
+    4. Changed plus, difference, times and remainder to +&, -&, * and \\.
+    5. Changed greaterp and lessp to >& and <&.
+    6. Changed minusp to (<& ..  0)
+    7. Changed (neq 0 ..) to (not (=& 0 ..)).
+    8. Eliminated the intermediate exprs insertdb1, fetch1, etc.
+    by converting the basic functions insertdb, fetch to use the
+    &optional syntax.
+PRELIMINARY RESULTS:
+    25-33% speedup of various test programs.
+
+10/20/82
+--- Added abbreviation "pdb" for "printdb".
+--- Changed usage of nth, push and pop to use Franz Opus 38.32's new
+definitions of them, removing them from ucisubset.l.
+
+9/17/82
+--- Changed scopy, patternize and varreplace to exprs from macros
+so that they will compile without complaints of special variables.
+
+9/16/82
+--- Added new hashing mechanism using label && and called "hash
+focusing".  If this is found when inserting into the database
+then the item is hashed as if it were the item in the slot so
+labelled.  This is designed for people using a data base all of
+whose entries are of the same type (not required, just common
+for this application) and enables the contents of a slot to be
+more usefully used to discriminate them (e.g., planfors, inference
+rules, or almost any such extremely-common binary predicates.)
+At fetching time, && is considered less useful than *** or ** and more
+useful than * or nothing (subject to debate and change).  (This
+necessitated the addition of an additional entry in the header of
+structure definitions, moving everything else down a slot in the hunk.)
+This differs from & (hash aliasing) in that && hash focussing affects
+how a structure itself is inserted and fetched, while & simply
+affects how structures containing this type of structure are
+treated.  For example, suppose the unique numbers of A, B, and C
+respectively are 1, 2, and 3.  C is a symbol.  A has one slot X with
+* and && hashing.  B has one slot Y of type symbol with * hashing.
+Then a structure like (A (X (B (Y C)))) will be indexed the
+following ways and fetcheverywhere will find it in the following
+order:
+    && which uses the 2 and 3 from B and its C, (ignoring the 1 of A),
+           and also simply 2 from B.
+    * on A uses type of B thus using 1 and 2.
+    also put under 1 of A without using 2 or 3.
+If B had an & in its slot then the
+    * on A is affected by & on B thus using 1 and 3 (ignoring the 2 of B).
+
+Thus, if you consider A, B, and C to be three levels of information
+in the structure, an item can be hashed under any combination of two
+of those levels.  The normal * method uses levels 1 and 2, the
+aliasing & method ignores level 2 and uses levels 1 and 3, and the
+new focussing && method ignores level 1 and uses levels 2 and 3.
+In addition, the item can be put under 1, 2 or 3 individually by
+various combinations of marks (1 = none, 2 = :, 3 = :+&).  The only
+unavailable combination of the 3 is all three.
+
+(Added internal-use-only functions are insertbyfocus, removebyfocus,
+puthashfocus, gethashfocus, recursetoinsidestandardfetch.
+
+9/15/82
+--- Added two functions "memmatch" and "memstrequal" which are like
+"memq" except that they use "match" and "strequal" respectively
+instead of "eq".
+--- Added fixes to "scopy" and "patternize" from Dave Chin which allow
+them to handle circularly linked structures AND to use the same copy
+of the same structure wherever it appears.  This required the addition
+of a special variable *scopieditems*.  This also included a bug fix
+which added code to store pointers to the new copies in the
+abbreviation atoms stored in them.
+--- Added a function called "varreplace" similar to "patternize" which
+replaces all bound variables in an item with their values, in effect
+permanently freezing them.
+--- Added a function called "(intscopy item outeritem)" where intscopy
+stands for "internal scopy" exactly the same as "(scopy item)" except
+it does the copying as if the item were internal to outeritem, thus
+sharing its local and block variables.
+--- Split create.l into create.l and scopy.l.
+
+9/14/82
+--- Moved much of the initialization stuff out of pearl-top-level-init
+to be done at load time instead.  This cut the minimum startup cost
+for PEARL from 4 seconds to 0.8 seconds CPU.
+--- Changed setdbsize to remove all current databases before changing
+the size, warn if *warn* is set and recreate *maindb* with *db*
+pointing to it.  Also fixed a bug when removing the last database.
+--- Changed the init-files processing to parallel the new Franz method,
+looking in the current directory, and then the home directory, and
+looking for .init.prl followed by .o, .l or nothing, and then init.prl
+followed by .o, .l or nothing.  Similarly for start.prl.
+--- Fixed cleardb so that it doesn't make new cons-cells for the buckets
+and so that it uses connectdb if the database has a parent.  Thus,
+cleardb is a local database clearer and its effects do not extend up
+the DB hierarchy.
+
+6/6/82
+Added new hashing method.  If slots are labelled with *** and all
+slots so marked are filled with useful values, then the item is hashed
+under the type of structure plus the values of all these slots.
+New functions are gethashmulti and puthashmulti.  *multiproducts* is a
+new special atom containing the numbers to multiply the various values
+with to produce the index (currently powers of 16).
+
+6/3/82
+Fixed a bug in fetcheverywhere which caused it to only find the
+bucket for the first *-ed slot, instead of all of them.  (Added
+to npearl also).
+
+5/28/82
+Tried replacing the sequential search method of finding slot numbers
+for particular slot names with evaluating a concat'ed atom made out
+of <typename ":" slotname> but timings found it slower so it was
+removed.
+
+5/27/82
+Fixed a problem with storage of variables.  Instead of two spots in
+the hunk, one for the alist (unfrozen variables) and one for the
+alistcp (frozen variables), there is a special cons cell with these
+in its car and cdr.  This cons cell is pointed to by all substructures
+so that they can be used in fetches and matches and will be able to
+unbind or freeze or thaw their variables.  Additional special variable
+is *toplevelalists* (or some such).
+
+5/6/82
+--- When an individual (including default instance) structure is created,
+an abbreviation atom is stored in it.  This abbreviation is chosen as
+follows:
+    1.  If the option of having a structure stored in an atom is used,
+    then that atom is the one used as an abbreviation.  Thus
+       (create individual x Pete)
+    will have Pete as a abbreviation.
+    2.  If that option isn't used, then default instances will be
+    given the abbreviation i:x (where x is the structure type name)
+    and individuals at the top level will be given a name newsym-ed
+    from the name of their type.  Thus
+       (create base x)  will make a default instance abbreviated i:x and
+       (create individual x) will be abbreviated x0 or x1 or whatever.
+--- New printing and "form-type" functions were added called "abbrevprint"
+and "abbrevform" which print the abbreviation (if there is one) for
+any structure below the top level.
+--- The base name of the type of a slot (i.e., the last word, after
+setof's are stripped off) is stored for each slot (a more general
+application of the "ppset" information always stored for integer slots
+with ordinal types before).  This is in preparation for two things:
+    1. Enforcing such type descriptions.
+    2. Generating knowledge about the slots of a structure so that the
+    user need not know whether to use fetch or path.
+
+5/5/82
+The name of an old slot in a new expanded may be changed by following
+the new name by the old slotname preceded with an equal sign.  Thus
+for example:
+pearl> (create base X
+              (A struct))
+(X (A (nilstruct)))
+pearl> (create expanded X Y
+              (B =A)
+              (C .....))
+(Y (B (nilstruct)) (C .....)))
+
+NOTE that there MAY NOT be a space between the equal sign and the A
+since = is the read macro which expands =A into (*slot* A) but leaves
+a single space-surrounded = alone.
+
+4/28/82
+--- Adapted PEARL to fit Franz Opus 38.13 so that the atoms
+showstack-printer and trace-printer are bound to the functions
+pearlshowstackprintfn and pearltraceprintfn. (Note the addition of
+"pearl" to the beginning of these).  Also changed the name of
+breakprintfn to pearlbreakprintfn but it is not currently
+lambda-bindable.
+--- Adapted the reading of .init.prl and .start.prl files to disable
+the printing of "[load .init.prl]" by lambda-binding $ldprint to nil
+first (Franz Opus 38.14).
+
+2/22/82
+--- Fixed a bug in the hook disablers.   The atoms for path hooks
+were misnamed in such a way that you couldn't use hidden and
+visible.   Instead of *rungethooks*, and other *run...hooks*
+forms, they are now *rungetpathhooks* and other *run...pathhooks*.
+Note that they must be called as (XXXpath ...) and not (path XXX ...)
+when used with hidden and visible.
+
+2/21/82
+--- Added ability to evaluate an atom when expecting a value of a
+different type (besides integers which already worked this way).
+For symbols, this is done if the atom isn't a symbol name.
+For structures, it must evaluate to a structure.
+For Lisp slots, it may not evaluate to an atom.
+For setof slots, its value is checked for being of the appropriate
+type, including depth of nesting.
+--- Added the fetching function "fetcheverywhere" which gathers
+ALL the buckets the object could have been hashed into and builds
+a stream out of all of them (potentially five buckets).  Will wait
+to build an "expandedfetcheverywhere" with its potential of
+returning 5 times the-depth-of-the-hierarchy buckets.
+
+vi: set lisp:
diff --git a/usr/src/ucb/lisp/pearl/Makefile b/usr/src/ucb/lisp/pearl/Makefile
new file mode 100644 (file)
index 0000000..050b0af
--- /dev/null
@@ -0,0 +1,87 @@
+
+#      Makefile for pearl 
+
+# Read the ReadMe file for more info.
+# This makefile creates these things:
+#   pearl - the executable PEARL, loaded into a lisp.
+#   pearl.o - the object version of PEARL's functions for fasl'ing
+#             into another lisp file at compile time.
+#   tags - tags file for PEARL source.
+#
+
+# If LibDir is changed, you must also change the pathnames in pearllib.l
+LibDir = /usr/lib/lisp
+CopyTo = /dev/null
+ManDir = /usr/man/man1
+ObjDir = /usr/ucb
+Liszt = ${ObjDir}/liszt
+CdTo = ..
+
+Src =  alias.l create.l db.l fix.l franz.l hash.l history.l hook.l \
+       inits.l lowlevel.l match.l path.l pearl.l \
+       pearlbase.l pearlbulk.l pearllib.l pearlsmall.l \
+       print.l scopy.l symord.l \
+       toplevel.l ucisubset.l vars.l
+
+AllSrc =  Makefile ChangeLog ReadMe implement.ms ltags \
+       manual.ms pearl.1 ptags template update.ms ${Src}
+
+.l.o:
+       ${Liszt} $<
+
+# Make "pearl.o" and "pearl" from scratch.
+# NOTE: At installations where memory is less than 2.5Mb,
+#    "make pearl" normally makes "small" which builds PEARL in two steps.
+#    If your installation has more memory, "pearl" can be changed to
+#    make "big" instead.  In this case, "install" below should also be
+#    changed to make "biginstall" instead of "smallinstall".
+pearl: small
+       echo "(savepearl)" | pearl.o
+       @echo pearl done
+
+pearlbase.o:   pearlbase.l
+
+pearlbulk.o:   pearlbase.o pearlbulk.l
+
+small: pearlbase.o pearlbulk.o
+       ${Liszt} -r pearlsmall.l -o pearl.o
+
+big:
+       ${Liszt} -r pearl.l
+
+# Install the executable pearl in ObjDir and the
+#   fasl'able pearl.o for compiling code using PEARL in LibDir.
+#   NOTE: "install" can be changed to use "biginstall" on big enough machines.
+install: smallinstall
+
+smallinstall: small
+       echo "(savepearl)" | pearl.o
+       mv pearlbase.o ${LibDir}/pearlbase.o
+       mv pearlbulk.o ${LibDir}/pearlbulk.o
+       ${Liszt} -r pearllib.l -o pearl.o
+       mv pearl.o ${LibDir}/pearl.o
+       mv pearl ${ObjDir}/pearl
+       cp pearl.1 ${ManDir}/pearl.1
+       @echo pearl done
+
+biginstall: big
+       echo "(savepearl)" | pearl.o
+       mv pearl.o ${LibDir}/pearl.o
+       mv pearl ${ObjDir}/pearl
+       cp pearl.1 ${ManDir}/pearl.1
+       @echo pearl done
+
+tags:  /dev/tty  ${Src}
+       -rm -f tags
+       awk -f ltags ${Src} | sort > tags
+
+# For distribution purposes.
+copysource: ${AllSrc}
+       (tar cf - ${AllSrc} | (cd ${CopyTo} ; tar xf -))
+
+scriptcatall: ${AllSrc}
+       @(cd ${CdTo} ; scriptcat pearl pearl ${AllSrc})
+
+clean:
+       -rm -f pearl pearl.o
+
diff --git a/usr/src/ucb/lisp/pearl/ReadMe b/usr/src/ucb/lisp/pearl/ReadMe
new file mode 100644 (file)
index 0000000..3021cc6
--- /dev/null
@@ -0,0 +1,127 @@
+ReadMe file for the distribution of the Franz implementation of PEARL.
+                                                8/9/83 by Joe Faletti
+
+PEARL is an AI programming language implemented on top of Franz Lisp
+by Joseph Faletti and Michael Deering under the direction of Robert
+Wilensky at the Berkeley AI Research Project (BAIR).
+
+DOCUMENTATION
+    For more information on PEARL's capabilities, see the following:
+
+[1] Deering, M., Faletti, J., and Wilensky, R.  1981.  PEARL:  An Efficient
+Language for Artificial Intelligence Programming.  In the Proceedings
+of the Seventh International Joint Conference on Artificial Intelligence.  
+Vancouver, British Columbia.  August, 1981.
+
+[2] Deering, M., Faletti, J., and Wilensky, R.  1982.  The PEARL Users Manual.
+Berkeley Electronic Research Laboratory Memorandum No.
+UCB/ERL/M82/19.  March, 1982.
+
+[3] Faletti, J., and Wilensky, R.  1982.  The Implementation of PEARL.
+Unpublished memo. 
+
+The last two are included in vtroff source form in this distribution
+but the page numbers of [2] may be off by a bit (sorry! -- if someone
+bothers to convert the manual for automatic table of contents and
+index generation, we'd be happy to use it!).  (More below).
+
+The manual [2] may be printed and distributed to users with no fear
+of copyright infringement.  However, for those without suitable printing
+facilities, a single photocopy of the manual suitable for auto-feed copying
+for local distribution of the manual may be acquired from:
+    Berkeley AI Research Project
+    Robert Wilensky, Director
+    Computer Science Division
+    553 Evans Hall
+    University of California, Berkeley
+    Berkeley, CA  94720
+This version will include an addendum summarizing the changes
+described in the file ChangeLog.
+
+BUG REPORTS:
+    Bug reports should be mailed to Pearl-Bugs@Berkeley by ARPANET or
+ucbvax!pearl-bugs by USENET.  PEARL is being provided as is for the
+cost of distribution with Franz and as such carries no warranty or
+guarantee.
+
+CONTENTS OF THIS DIRECTORY:
+    The files in this directory fall into two categories: A) the source and
+make file for building a version of PEARL in Franz and B) documentation.
+
+    A) Source and make file for building a version of PEARL in Franz.
+These files are described briefly after the following description of
+how to make a version of PEARL.
+
+To Make PEARL:
+    A version of PEARL may be made by changing to this directory and
+executing a "make pearl".  As delivered, this makes "small" which compiles
+PEARL in two pieces, and builds "pearl.o" (which loads the two pieces
+into a lisp) and then executes the "savepearl" function which dumps a
+lisp called "pearl" in the current directory containing all of PEARL
+with the PEARL top level installed and ready to start up from scratch.
+This form is necessary on machines with less than about 2.5Mb of memory.
+If your installation is larger, you can change "pearl" to make "big"
+instead of "small" and change "install" to make "biginstall" instead
+of "smallinstall".  This will compile PEARL in one piece, creating
+"pearl.o" simply by compiling the file "pearl.l" which "includes" all
+the other source files described below.
+    Making PEARL from scratch takes about 13 minutes of CPU time, or about
+15 minutes of real time (times the load average) on a VAX 780.
+    To install the executable pearl in the usual object directory,
+/usr/ucb, and the load module pearl.o in the Franz library /usr/lib/lisp,
+execute a "make install".  If you change where the library is you must
+also change the absolute path names in the file "pearllib.l" (which is used
+in a "make small" to make it easy to load the two halves of PEARL with a
+single file).
+
+The Source for PEARL:
+    The source for PEARL is described below in the order that it is
+included in "pearl.l".
+
+ucisubset.l --- PEARL was originally implemented in UCILisp.  This file
+    defines those functions from UCILisp still used in PEARL.
+franz.l --- Franz version of functions that are likely to need
+    to be redefined for a particular lisp.
+lowlevel.l --- Lowest level functions (mostly macros) in PEARL
+    used to access the various data structures.
+db.l --- Functions for creating databases.
+vars.l --- Functions to handle pattern-matching variables.
+symord.l --- Functions for creating symbols and ordinals.
+hook.l --- Functions used by everything else to handle hooks (demons).
+create.l --- Functions to create PEARL structures.
+scopy.l --- Functions to copy PEARL structures.
+path.l --- The PATH function.
+print.l --- Functions to print PEARL objects.
+hash.l --- Functions using hashing info in structures to insert and
+    fetch from data bases.
+match.l --- Functions to match and/or compare structures.
+history.l --- Functions used to implement the history mechanism in the
+    toplevel loop.
+toplevel.l --- Variation on the Franz toplevel loop for PEARL,
+    including functions for dumping various versions of a running PEARL.
+fix.l --- Variation on the "fixit" debugger adapted for PEARL.
+alias.l --- Code to save various functions under alternative names.
+inits.l --- Code which must run at load time to initialize a PEARL
+    environment.
+
+Documentation included in this directory:
+
+manual.ms --- The -ms source of the PEARL manual as published in the
+    reference [2] above.  This should be vtroffable to produce a copy
+    of the PEARL manual, although the page numbers were done by hand
+    and thus may be off by a bit if anything is changed.  It may also
+    be nroffed, although the page numbers will most certainly be off.
+update.ms --- The -ms source for an update to the manual covering PEARL
+    up through Version 3.9 paginated for appending to the manual.
+ChangeLog --- A listing in reverse date order of things changed in
+    PEARL since the manual was published.
+template --- Visual representation of the allocation of information in
+    the hunks used by PEARL for various internal data structures.
+implement.ms --- An unfinished memo on the implementation of PEARL.
+    Includes a simple example of how to implement forward and backward
+    chaining in PEARL and a bit more detail on the hashing mechanism.
+ltags --- A tags file for the various function and macro definition
+    mechanisms used in PEARL (more than standard Franz).
+ptags --- A tags file for files which contain mixed Lisp functions and
+    PEARL structure definitions.
+
diff --git a/usr/src/ucb/lisp/pearl/create.l b/usr/src/ucb/lisp/pearl/create.l
new file mode 100644 (file)
index 0000000..10f7668
--- /dev/null
@@ -0,0 +1,942 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;; create.l ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Functions for creating, copying, and merging structures.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright (c) 1983 ,  The Regents of the University of California.
+; All rights reserved.  
+; Authors: Joseph Faletti and Michael Deering.
+
+; Create a new structure of one of the five types:
+;     BASE:        build a new structure with all new slots.
+;     EXPANDED:    build new slots in addition to slots inherited from
+;                     a BASE or EXPANDED structure.
+;     INDIVIDUAL:  create an instance of a BASE or EXPANDED structure,
+;                     filling in slots or inheriting defaults from above.
+;     PATTERN:     create an instance of a BASE or EXPANDED structure but
+;                     fill in unspecified slots with ?*ANY*.
+;     FUNCTION:    build a new structure with slots describing the
+;                     arguments to the function.
+; Generalized syntax for this function is:
+;
+; (CREATE <StructureType> <ExpandedorBaseName> <NewItemName>
+;         [{HashingInfo} <OldSlotName> {{{:=} <SlotValue>} | ^}
+;                        { : <Variable> }
+;                        {<ListOfRestrictionStructureOrSlotIfNames>} ]
+;    . . . . . . .
+;         [{HashingInfo} <NewSlotName> <Type> {{{:=} <SlotValue>} | ^}
+;                        { : <Variable> }
+;                        {<ListOfRestrictionStructureOrSlotIfNames>} ] )
+; BASE structures have no <ExpandedorBaseName> and only new slots.
+; EXPANDED structures should have at least one new slot and inherit
+;       default values from the <ExpandedorBaseName>.
+; INDIVIDUAL structures have only old slots and inherit default values from
+;       the <ExpandedorBaseName>;  if the <NewItemName> occurs, the atom
+;       <NewItemName> is set to point to the internal form which is also
+;       returned as the value of CREATE.
+; PATTERN structures have only old slots and all unspecified slots are
+;       set to ?*ANY* rather than inheriting a default.
+; FUNCTION structures have no <ExpandedOrBaseName> and only new slots.
+;       They are interpreted as functions to be run rather than structures
+;       to be accessed when they are MATCHed, FETCHed or PATHed.
+;
+; The structure created is always stored in the SPECIAL variable *LASTCREATED*
+;       in addition to the <NewItemName> if specified and the atom formed
+;       by prepending a 'd:' to the front of the <ExpandedOrBaseName>.
+;
+; If the SlotValue for a slot in a BASE or EXPANDED structure is preceded
+;       by a :=, then the slot is filled with this value but it is not
+;       used as the default for this slot in future INDIVIDUALS and
+;       EXPANDEDS.
+; If the SlotValue is not preceded by a :=, then the value represents a
+;       default to be inherited by INDIVIDUALs and new EXPANDEDS.
+; This just sets the two atoms *toplevelp* and *currentcreatetype*
+;   and calls the real workhorse "insidecreate".
+(df create (l)
+  (setq *toplevelp* t)
+  (setq *currentcreatetype* (car l))
+  (apply (function insidecreate) l))
+; Pick apart the atoms before the slots, handle them and pass the
+;    rest on to the appropriate version of create XXX.
+(df insidecreate (l)
+  (let ((type (car l))
+       (abbrev (cond (*toplevelp* '*buildabbrev*)
+                     ( t nil)))
+       (name1 (cadr l))
+       (name2 (caddr l))
+       (name3 (cadddr l))
+       slots)
+       (cond ((reallitatom name2)
+             (setq abbrev name2)
+             (setq slots (cdddr l))
+             (cond ((reallitatom name3)
+                    (setq abbrev name3)
+                    (setq slots (cddddr l)))
+                   ( t  (setq name3 name2))))
+            ( t (setq name3 (setq name2 name1))
+                (setq slots (cddr l))))
+       (and (memq type '(ind individual pat pattern))
+           (eq name1 name3)
+           (setq name3 '*lastcreated*))
+       (set name3
+           (setq *lastcreated*
+                 (selectq type
+                          ((individual ind)
+                           (createindividual name1 abbrev slots))
+                          (base
+                           (createbase name1 abbrev slots))
+                          ((expanded exp)
+                           (createexpanded name1 name2 abbrev slots))
+                          ((pattern pat)
+                           (createpattern name1 abbrev slots))
+                          ((function fn)
+                           (createfunction name1 abbrev slots))
+                          (otherwise (msg t "CREATE: Illegal selector: " type
+                                          " in created structure: " l t)
+                                     (pearlbreak)))))))
+; Create a new structure and insert it in the database.
+(defmacro dbcreate (&rest rest)
+  `(insertdb (create .,rest)))
+
+(defmacro cb (&rest rest)
+  `(create base .,rest))
+
+(defmacro ci (&rest rest)
+  `(create individual .,rest))
+
+(defmacro ce (&rest rest)
+  `(create expanded .,rest))
+
+(defmacro cp (&rest rest)
+  `(create pattern .,rest))
+
+(defmacro cf (&rest rest)
+  `(create function .,rest))
+(defmacro base (&rest rest)
+  `(create base .,rest))
+
+(defmacro ind (&rest rest)
+  `(create individual .,rest))
+
+(defmacro individual (&rest rest)
+  `(create individual .,rest))
+
+(defmacro pexp (&rest rest)
+  `(create expanded .,rest))
+
+(defmacro expanded (&rest rest)
+  `(create expanded .,rest))
+
+(defmacro pat (&rest rest)
+  `(create pattern .,rest))
+
+(defmacro pattern (&rest rest)
+  `(create pattern .,rest))
+
+(defmacro fn (&rest rest)
+  `(create function .,rest))
+(defmacro pfunction (&rest rest)
+  `(create function .,rest))
+;  Put a *VAR* variable in the structure's assoc-list and return the cons-cell.
+(defmacro installvar (varname)
+  `(cond ((eq '*any* ,varname) *any*conscell*)
+        ; else, if there, return it.
+        ((assq ,varname (getalist *currenttopcreated*)))
+        ; else, add it (which also returns the special conscell).
+        (  t   (addalist ,varname *currenttopcreated*))))
+; Install an adjunct variable in the slot.
+(defmacro installadjunct (adjunctvar)
+  `(let (var)
+       (cond ((dtpr ,adjunctvar)
+              (setq var (cadr ,adjunctvar))
+              (selectq (car ,adjunctvar)
+                       (*var* (installvar var))
+                       (*global* var)
+                       (otherwise
+                        (msg t "CREATE: no adjunct variable given after colon "
+                             "-- rest of slot is: " ,adjunctvar slot t)
+                        (pearlbreak))))
+             (  t  (msg t "CREATE: no adjunct variable given after colon. "
+                        "Rest of slot is: " ,adjunctvar slot t)
+                   (pearlbreak)))))
+
+(dm handlepossibleadjunctvar (none) ; but assumes SLOT, SLOTVALUE, & VALUETYPE.
+  '(let ((adjunctvar (car slot)))
+       (and (eq adjunctvar ':)
+            (cond ((neq valuetype 'CONSTANT)
+                   (msg t "CREATE: Adjunct variables not allowed in "
+                        "slots whose values are also variables." t)
+                   (pearlbreak))
+                  ( t (setq slot (cdr slot)) ; throw away ":".
+                      (setq adjunctvar (pop slot))
+                      (setq valuetype 'ADJUNCT)
+                      (setq slotvalue (cons slotvalue
+                                            (installadjunct adjunctvar))))))))
+
+; Ensure that value is of type TYPENUM (used after ! or on value in atom
+;    where setof value expected).  Value returned (t / never) is used
+;    only in evaluating atom.  If error, doesn't return.
+(de enforcetype (value typenum)
+  (or (selectq typenum
+              (0 (structurep value))
+              (1 (psymbolp value))
+              (2 (numberp value))
+              (3 (not (reallitatom value)))
+              (otherwise
+               (apply (function and)
+                      (mapcar (funl (singlevalue)
+                                    (enforcetype singlevalue
+                                                 (- typenum 4)))
+                              value))))
+      (progn (msg t "CREATE: Value after ! or bound to atom in SETOF "
+                 "slot is of wrong type.  Value is: " value t)
+            (pearlbreak))))
+
+; Get the value for a slot.
+; If preceded by an ! then it is already in internal form but verify this.
+; If is preceded by a $ then it should be evaluated before continuing
+;    processing (on its value).
+(dm constructvalue (none)
+  '(let ((typenum (getslottype slotnum defblock))
+        (ppset   (getppset    slotnum defblock)))
+       (selectq (car slot)
+                (\!  (setq slot (cdr slot))
+                     (setq newvalue (eval (pop slot)))
+                     (enforcetype newvalue typenum)
+                     (setq valuetype 'CONSTANT)
+                     (setq slotvalue newvalue))
+                (\$  (setq slot (cdr slot))
+                     (setq newvalue (eval (pop slot)))
+                     (setq valuetype 'CONSTANT)
+                     (setq slotvalue (buildvalue newvalue typenum ppset)))
+                (otherwise
+                 (cond ((and (dtpr (car slot))
+                             (eq (caar slot) '*var*))
+                        (setq valuetype 'LOCAL)
+                        (setq newvalue (cadr (pop slot)))
+                        (setq slotvalue (installvar newvalue)))
+                       ((and (dtpr (car slot))
+                             (eq (caar slot) '*global*))
+                        (setq valuetype 'GLOBAL)
+                        (setq slotvalue (cadr (pop slot))))
+                       (  t  (setq valuetype 'CONSTANT)
+                             (setq slotvalue
+                                   (buildvalue (pop slot) typenum ppset))))))))
+; Generate the default value for slots of the given type.
+(defmacro defaultfortype (typenum)
+  `(selectq ,typenum
+           (0 (eval (instatom 'nilstruct)))
+           (1 (eval (symatom 'nilsym)))
+           (2 0)
+           (3 nil)))
+; Look at the ISA to find the default value, or the else use
+;    the default default for that type.
+(defmacro inheritvalue (structdef)
+  `(let ((isa ,structdef))
+       (cond ((or (null isa)
+                  (not (getenforce slotnum isa)))
+              (setq slotvalue (defaultfortype (getslottype slotnum defblock)))
+              (setq valuetype 'CONSTANT))
+             ( t (let ((default (getdefaultinst isa)))
+                      (setq slotvalue (getslotvalue slotnum default))
+                      (setq valuetype (getslotvaluetype slotnum default)))))))
+; Look for predicates and hooks.  Use tconc to keep in order.
+(dm handlepredicatesandhooks (none)
+  '(progn
+    (setq predlist (ncons nil))
+    (setq slothooklist (ncons nil))
+    (while (setq fcn (pop slot))
+          (cond ((atom fcn)
+                 (cond ((eq fcn 'instead)
+                        ; Don't inherit hooks.
+                        (putpred slotnum nil valblock))
+                       ((memq fcn '(if hook))
+                        ; A hook follows.
+                        (tconc slothooklist (cons (pop slot) (pop slot))))
+                       ; Structure predicate.
+                       ((structurenamep fcn)
+                        (tconc predlist (eval (defatom fcn))))
+                       ; Otherwise, a predicate name.
+                       ( t (tconc predlist fcn))))
+                ; Otherwise an s-expression predicate.
+                ( t (tconc predlist fcn))))
+    (putpred      slotnum
+                 (nconc (car predlist) (getpred slotnum valblock))
+                 valblock)
+    (putslothooks slotnum
+                 (nconc (car slothooklist) (getslothooks slotnum valblock))
+                 valblock)))
+
+; Build a new slot in the current structure.
+(dm buildslot (none)
+  '(progn
+    (setq slotname (pop slot))
+    (clearhashandformat slotnum defblock)
+    ; To gather hashing and enforce information before installing in defblock.
+    (setq hashcollect 0)
+    (setq reqstruct nil)
+
+    ; Check for hashing marks first.
+    (while (selectq slotname
+                   ; First starred slot used for > hashing if no & present.
+                   (*   (and (\=& 0 first*edslot)
+                             (setq first*edslot (minus slotnum)))
+                        (addhash*   hashcollect))
+                   (**  (addhash**  hashcollect))
+                   (*** (addhash*** hashcollect))
+                   (&   (cond ((not (\=& 0 hashalias))
+                               (msg t "CREATE: Only 1 hash alias (&) or "
+                                    "selected slot (^) allowed in: "
+                                    newname t)
+                               t)
+                              ( t (setq hashalias slotnum))))
+                   (^   (cond ((not (\=& 0 hashalias))
+                               (msg t "CREATE: Only 1 hash alias (&) or "
+                                    "selected slot (^) allowed in: "
+                                    newname t)
+                               t)
+                              ( t (setq hashalias (minus slotnum)))))
+                   (&&  (cond ((not (\=& 0 hashfocus))
+                               (msg t "CREATE: Only 1 hash focus (&&) "
+                                    "allowed in: " newname t)
+                               t)
+                              ( t (setq reqstruct t)
+                                  (setq hashfocus slotnum))))
+                   (:   (addhash:   hashcollect))
+                   (::  (addhash::  hashcollect))
+                   (>   (addhash>   hashcollect))
+                   (<   (addhash<   hashcollect)))
+          (setq slotname (pop slot)))
+    (and (\=& 0 (length slot))
+        (progn (msg t "CREATE: Missing slot name and/or type in slot number "
+                    slotnum " of structure: " newname t)
+               (pearlbreak)))
+
+    ;  Slotname now holds the slotname.  Should be checked for duplicates!!
+    (putslotname slotnum (ncons slotname) defblock)
+
+    ; Now look for the type.
+    (setq typenum 0)
+    (setq slottype (pop slot))
+    (while (selectq slottype
+                   (struct (setq reqstruct nil)
+                           nil)     ; i. e., add 0 to TYPENUM.
+                   (symbol (setq typenum (1+ typenum))  nil)
+                   (int    (setq typenum (+ 2 typenum))  nil)
+                   (lisp   (cond ((not (\=& 0 typenum))
+                                  (msg t "CREATE: <setof lisp> not allowed. "
+                                       "Type changed to <lisp> in slot "
+                                       slotname " of " newname t)
+                                  (setq typenum 3) nil)
+                                 ((not (\=& 0 hashcollect))
+                                  (setq hashcollect 0)
+                                  (msg t "CREATE: No hashing allowed on "
+                                       "<lisp> slots in slot " slotname
+                                       " of " newname t)))
+                           (setq typenum 3) nil)
+                   (setof (setq typenum (+ 4 typenum))    t)
+                   (otherwise
+                    ; Either an ordinal type ==> integer,
+                    ;   or a structure name ==> struct, or an error.
+                    (cond ((memq slottype *ordinalnames*)
+                           (setq typenum (+ 2 typenum)) nil)
+                          ((structurenamep slottype)
+                           (setq reqstruct nil)
+                           nil)     ; i. e., add 0 to TYPENUM.
+                          (  t  (msg t "CREATE: Illegal type: " slottype
+                                     " in slot: " slotname " of " newname t)
+                                nil))))
+          (setq slottype (pop slot)))
+    (and reqstruct
+        (progn (msg t "CREATE: && hashing only allowed on STRUCT slots."
+                    t " Bad slot is called " slotname
+                    " and is of type " slottype t)
+               (pearlbreak)))
+    ; Save the last word of the type which is possibly a structure or
+    ; ordinal type name for future use.
+    (putppset slotnum slottype defblock)
+    (putslottype slotnum typenum defblock)
+
+    ; Next, look for a value, or ^ to inherit from above;
+    ;     these may be preceded by := or == to determine future
+    ;     "enforcing" (should be less strong term) of this default.
+    (setq slotvalue nil)
+    (setq valuetype nil)
+    (setq enforce (pop slot))
+    (selectq enforce
+            (:\=  (cond ((eq (car slot) '^)
+                         (setq slot (cdr slot))
+                         (inheritvalue nil))
+                        ( t (constructvalue))))
+            (\=\= (addenforce hashcollect)
+                  (cond ((eq (car slot) '^)
+                         (setq slot (cdr slot))
+                         (inheritvalue nil))
+                        ( t (constructvalue))))
+            ((^ nil)
+             (addenforce hashcollect)
+             (inheritvalue nil))
+            (otherwise (push enforce slot)
+                       (addenforce hashcollect)
+                       (constructvalue)))
+
+    (handlepossibleadjunctvar)
+
+    ; Hash, enforce, slotvalue and valuetype can now be installed.
+    (puthashandenforce slotnum hashcollect defblock)
+    (putslotvaluetype  slotnum valuetype   valblock)
+    (putslotvalue      slotnum slotvalue   valblock)
+
+    (handlepredicatesandhooks)))
+; Create a new structure of type BASE:  a structure with ALL NEW slots.
+(de createbase (newname abbrev slots)
+  (and (eq newname 'nilstruct)
+       (boundp (defatom 'nilstruct))
+       (progn (msg t "CREATE BASE: Cannot redefine nilstruct." t)
+             (pearlbreak)))
+  (and (structurenamep newname)
+       *warn*
+       (msg t "CREATE BASE: Warning: Creating a new definition"
+           " of an existing structure: " newname t))
+  (prog (defblock slotname slottype enforce fcn ppset slot length isa
+                 typenum valblock predlist slothooklist
+                 first*edslot basehooks basehookbefore newvalue reqstruct
+                 hashalias hashfocus hashcollect slotvalue valuetype)
+
+       ; Process base hooks if the first "slot" is named "if" or "hook".
+       (cond ((memq (caar slots) '(if hook))
+              (setq basehookbefore (cdr (pop slots)))
+              (setq basehooks (ncons nil))
+
+              ; Use tconc to preserve order.
+              (while basehookbefore ; is not NIL
+                     (tconc basehooks (cons (pop basehookbefore)
+                                            (pop basehookbefore))))
+              (setq basehooks (car basehooks)))
+             ( t (setq basehooks nil)))
+
+       ; Allocate hunks for definition and default instance (valblock)
+       ;     based on number of slots.
+       (setq defblock (allocdef (setq length (length slots))))
+       (setq valblock (allocval length))
+       (puttypetag '*pearldef* defblock)
+       (puttypetag '*pearlinst* valblock)
+       (cond (*toplevelp* (setq *currenttopcreated* valblock)
+                          (setq *currentpearlstructure* valblock)
+                          (initbothalists valblock)
+                          (setq *currenttopalists* (getbothalists valblock))
+                          ; Include the current environment in 
+                          ;    the variable assoc-list.
+                          (and *blockstack*
+                               (putalist (cdar *blockstack*) valblock))
+                          (setq *toplevelp* nil))
+             ( t (putbothalists *currenttopalists* valblock)))
+
+       (putdef defblock valblock)
+       (putdefaultinst valblock defblock)
+       (set (instatom newname) valblock)
+       (set (defatom newname) defblock)
+       (and abbrev
+            (cond ((eq abbrev '*buildabbrev*)
+                   (putabbrev (instatom newname) valblock))
+                  ( t (putabbrev abbrev valblock))))
+       (putuniquenum (newnum) defblock)
+       (putstructlength length defblock)
+       (putisa nil defblock)
+       (putexpansionlist nil defblock)
+       (putbasehooks basehooks defblock)
+       (putpname newname defblock)
+
+       (setq hashalias 0)
+       (setq hashfocus 0)
+       (setq first*edslot 0)
+       (for slotnum 1 length
+            (setq slot (pop slots))
+            (buildslot))
+
+       (cond ((\=& 0 hashalias) (puthashalias first*edslot defblock))
+             ( t  (puthashalias hashalias defblock)))
+       (puthashfocus hashfocus defblock)
+
+       (return valblock)))
+; Create a new individual just for this slot.
+(defmacro buildstructvalue (struct)
+  `(cond ((and (atom ,struct)                      ; if an atom
+              (boundp ,struct)                    ; and bound
+              (structurep (eval ,struct)))        ; to a structure,
+         (eval ,struct))                          ; evaluate it.
+        ; Otherwise, recursively call create.
+        ( t (selectq (car ,struct)
+                     ; New create type in slot.
+                     ((ind individual pat pattern fn function
+                           base exp expanded)
+                      (let ((*currentcreatetype* (car ,struct)))
+                           (apply (function insidecreate) ,struct)))
+                     (otherwise
+                      ; Otherwise, use current create type.
+                      (apply (function insidecreate)
+                             (cons *currentcreatetype* ,struct)))))))
+; Get a pointer to the symbol.
+(defmacro buildsymbolvalue (sym)
+  `(cond ((symbolnamep ,sym)   (eval (symatom ,sym)))
+        ; If not a symbol name, then ...
+         ((and (atom ,sym)                      ; if an atom
+              (boundp ,sym)                    ; and bound
+              (psymbolp (eval ,sym)))          ; to a symbol,
+         (eval ,sym))                          ; evaluate it.
+        ; Otherwise, error.
+        ( t  (msg t "CREATE: " ,sym " is used in a slot of type SYMBOL but "
+                  "neither is the name of a symbol nor evaluates to one." t)
+             (pearlbreak))))
+; Get an integer using PPSET if not an integer.
+(defmacro buildintvalue (intval bppset)
+  `(let (assocval)
+       (cond ((numberp ,intval) ,intval)
+             ; Ordinal type given for ppset.
+             ((and ,bppset    ; is not NIL.
+                   (setq assocval (assq ,intval (eval (ordatom ,bppset)))))
+              (cdr assocval))
+             ; Some other atom which is bound to an integer.
+             ((and (atom ,intval)
+                   (boundp ,intval)
+                   (numberp (eval ,intval)))
+              (eval ,intval))
+             ; Otherwise, error.
+             ( t (msg t "CREATE: Unbound atom or non-integer value: "
+                      ,intval " in integer slot." t) 
+                 (pearlbreak)))))
+; Construct a new value of the specified type using the pplist if necessary
+(de buildvalue (value typenum ppset)
+  (selectq typenum
+          (0 (buildstructvalue value))
+          (1 (buildsymbolvalue value))
+          (2 (buildintvalue    value ppset))
+          (3 value) ; i.e., could be anything they want.
+          (otherwise
+           (cond ((and (atom value)
+                       (boundp value)
+                       (enforcetype (eval value) typenum))
+                  (eval value))
+                 ( t (mapcar (funl (singlevalue)
+                                   (buildvalue singlevalue
+                                               (- typenum 4) ppset))
+                             value))))))
+; Return the position number of SLOTNAME in structure DEFBLOCK.
+(defmacro slotnametonumber (slotname defblock)
+  `(progn
+    (setq slotlocation 0)
+    (for slotnum 1 (getstructlength ,defblock)
+        (and (memq ,slotname (getslotname slotnum ,defblock))
+             (setq slotlocation slotnum)))
+    slotlocation))
+; Find the slotname in SLOT, put it in SLOTNAME, and find its SLOTNUM.
+(dm findslotnum (none)
+  '(progn
+    (setq slotname slot)
+    (while (memq (car slotname) '(* ** *** & ^ && : :: < > +))
+          (setq slotname (cdr slotname)))
+    (cond ((and (dtpr (cadr slotname))
+               (eq '*slot* (car (cadr slotname))))
+          (setq slotname (cadr (cadr slotname)))
+          (minus (slotnametonumber slotname olddefblock)))
+         ( t (setq slotname (car slotname))
+             (slotnametonumber slotname olddefblock)))))
+; Look up through ISA links and add name to Expansion Lists.
+;    Assumes PROG vars NEWNAME and OLDDEFBLOCK.
+(dm addtoexpansionlists (none)
+  '(progn
+    (setq isa olddefblock)
+    (while isa         ; is not null
+          (putexpansionlist (cons defblock (getexpansionlist isa)) isa)
+          (setq isa (getisa isa)))))
+; Copy definition for one slot.
+(dm copyslice (none)
+  '(progn
+    (putslottype      slotnum (getslottype      slotnum olddefblock) defblock)
+    (putslotname      slotnum (getslotname      slotnum olddefblock) defblock)
+    (putppset         slotnum (getppset         slotnum olddefblock) defblock)
+    (puthashandformat slotnum (gethashandformat slotnum olddefblock) defblock)))
+; Copy default values, predicates, and hooks for one slot.
+(dm copyslot (none)
+  '(progn
+    (putslotvaluetype slotnum (getslotvaluetype slotnum oldvalblock) valblock)
+    (putslotvalue     slotnum (getslotvalue     slotnum oldvalblock) valblock)
+    (putpred          slotnum (getpred          slotnum oldvalblock) valblock)
+    (putslothooks     slotnum (getslothooks     slotnum oldvalblock) valblock)))
+; Copy an old slot from an ISA into the current structure.
+(dm fillbaseslot (none)
+  '(progn
+    (cond ((<& slotnum 0)
+          (setq slotnum (minus slotnum))
+          (setq newslotnamep t))
+         ( t (setq newslotnamep nil)))
+
+    ; First check for changed hashing.
+    (setq slotname (pop slot))
+    (clearhashandformat slotnum defblock)
+    (setq hashcollect 0)
+    (while (selectq slotname
+                   (*   (and (\=& 0 first*edslot)
+                             (setq first*edslot (minus slotnum)))
+                        (addhash*   hashcollect) t)
+                   (**  (addhash**  hashcollect) t)
+                   (*** (addhash*** hashcollect) t)
+                   (&   (cond ((not (\=& 0 hashalias))
+                               (msg t "CREATE EXPANDED: Only 1 hash alias "
+                                    "(&) or selected slot (^) allowed in: "
+                                    newname t)
+                               t)
+                              ( t (setq hashalias slotnum))))
+                   (^   (cond ((not (\=& 0 hashalias))
+                               (msg t "CREATE EXPANDED: Only 1 hash alias "
+                                    "(&) or selected slot (^) allowed in: "
+                                    newname t)
+                               t)
+                              ( t (setq hashalias (minus slotnum)))))
+                   (&&  (cond ((not (\=& 0 hashfocus))
+                               (msg t "CREATE EXPANDED: Only 1 hash focus "
+                                    "(&&) allowed in: " newname t)
+                               t)
+                              ( t (setq hashfocus slotnum))))
+                   (:   (addhash:   hashcollect) t)
+                   (::  (addhash::  hashcollect) t)
+                   (>   (addhash>   hashcollect) t)
+                   (<   (addhash<   hashcollect) t)
+                   (+   (setq hashcollect (gethashinfo slotnum olddefblock))
+                        t))
+          (setq slotname (pop slot)))
+
+    (and (\=& 0 (length slot))
+        (progn (msg t "CREATE EXPANDED: Missing slot name and/or value in: "
+                    newname t)
+               (pearlbreak)))
+
+    (and newslotnamep
+        (pop slot)
+        (addslotname slotnum slotname defblock))
+
+    ; Next, check for value or ^, possibly preceded by := or ==.
+    (setq enforce (pop slot))
+    (selectq enforce
+            (:\= (cond ((eq (car slot) '^)  ; a waste.
+                        (setq slot (cdr slot))
+                        (inheritvalue (getisa defblock)))
+                       ( t (constructvalue))))
+            (\=\= (addenforce hashcollect)
+                  (cond ((eq (car slot) '^)
+                         (setq slot (cdr slot))
+                         (inheritvalue (getisa defblock)))
+                        ( t (constructvalue))))
+            ((^ nil)  (addenforce hashcollect)
+                      (inheritvalue (getisa defblock)))
+            (otherwise (push enforce slot)
+                       (addenforce hashcollect)
+                       (constructvalue)))
+    
+    (handlepossibleadjunctvar)
+
+    ; Hash, enforce, slotvalue and valuetype can now be installed.
+    (puthashandenforce slotnum hashcollect defblock)
+    (putslotvaluetype  slotnum valuetype   valblock)
+    (putslotvalue      slotnum slotvalue   valblock)
+
+    (handlepredicatesandhooks)))
+; Create a new structure of type EXPANDED:  build new slots in
+;    addition to slots inherited from a BASE or EXPANDED structure.
+(de createexpanded (basename newname abbrev slots)
+  (and (eq newname 'nilstruct)
+       (progn (msg t "CREATE EXPANDED: Cannot redefine nilstruct." t)
+             (pearlbreak)))
+  (and (structurenamep newname)
+       *warn*
+       (msg t "CREATE EXPANDED: Warning: Creating a new definition of "
+           "an existing structure: " newname t))
+  (or (structurenamep basename)
+      (progn (msg t "CREATE EXPANDED: " basename
+                 " is not the name of a previously declared structure." t
+                 "     New name is " newname ". Slots are: " slots t)
+            (pearlbreak)))
+  (prog (defblock valblock oldvalblock olddefblock slotname
+                 slottype enforce slot oldlength length slotnum
+                 typenum slotnumlist beginslots predlist slothooklist
+                 fcn ppset isa first*edslot slotlocation basehooks
+                 basehookbefore newvalue result item reqstruct
+                 newslotnamep hashalias hashfocus hashcollect
+                 slotvalue valuetype)
+       (setq olddefblock (eval (defatom basename)))
+       (setq oldlength (getstructlength olddefblock))
+       
+       ; Handle base hooks, if first "slot" is called "if" or "hook".
+       (cond ((memq (caar slots) '(if hook))
+              (setq basehookbefore (cdr (pop slots)))
+              (setq basehooks (ncons nil))
+              (while basehookbefore ; is not NIL
+                     (tconc basehooks (cons (pop basehookbefore)
+                                            (pop basehookbefore))))
+              (setq basehooks (nconc (car basehooks)
+                                     (getbasehooks olddefblock))))
+             ( t (setq basehooks (getbasehooks olddefblock))))
+       
+       ; Create a list of slotnumbers for the slotnames in SLOTS,
+       ; meanwhile also determining the LENGTH.
+       (setq beginslots slots)   ; save to process again.
+       (setq slotnumlist (ncons nil))
+       (setq length oldlength)
+       (while (setq slot (pop slots))
+              (cond ((not (\=& 0 (setq slotnum (findslotnum))))
+                     ; Old slot name or new name for old slot (negative).
+                     (tconc slotnumlist slotnum))
+                    ; Otherwise, new slot name: increase length.
+                    (  t   (setq length (1+ length))
+                           (tconc slotnumlist length))))
+       (setq slotnumlist (car slotnumlist))
+       (setq slots beginslots)
+       
+       ; Allocate new hunks.
+       (setq defblock (allocdef length))
+       (setq valblock (allocval length))
+       (puttypetag '*pearldef* defblock)
+       (puttypetag '*pearlinst* valblock)
+       (cond (*toplevelp* (setq *currenttopcreated* valblock)
+                          (setq *currentpearlstructure* valblock)
+                          (initbothalists valblock)
+                          (setq *currenttopalists* (getbothalists valblock))
+                          ; Include the current environment in 
+                          ;    the variable assoc-list.
+                          (and *blockstack*
+                               (putalist (cdar *blockstack*) valblock))
+                          (setq *toplevelp* nil))
+             ( t (putbothalists *currenttopalists* valblock)))
+
+       (putdef defblock valblock)
+       (putdefaultinst valblock defblock)
+       (set (instatom newname) valblock)
+       (set (defatom newname) defblock)
+       (and abbrev
+            (cond ((eq abbrev '*buildabbrev*)
+                   (putabbrev (instatom newname) valblock))
+                  ( t (putabbrev abbrev valblock))))
+       (putuniquenum (newnum) defblock)
+       (putstructlength length defblock)
+
+       ; Set up the hierarchy of ISAs.
+       (putisa olddefblock defblock)
+       (putexpansionlist nil defblock)
+       (addtoexpansionlists)
+
+       (putbasehooks basehooks defblock)
+       (putpname newname defblock)
+       (setq oldvalblock (getdefaultinst olddefblock))
+
+       ; (puthashalias 0   defblock)
+       (setq hashalias 0)
+       (setq hashfocus 0)
+       (or (<& (setq first*edslot (gethashalias olddefblock)) 0)
+           (setq first*edslot 0))
+       ; Copy old slots in first.
+       (for slotnum 1 oldlength
+            (copyslice)
+            (copyslot olddefblock))
+       ; Run base hooks attached to the base we are expanding.
+       (and (getbasehooks olddefblock)
+            (setq item valblock)
+            (checkrunhandlebasehooks1 '<expanded *runexpandedhooks*)
+            (setq valblock item))
+
+       ; For each slot, if it's new, build a new slot;
+       ;                if it's old, fill it in differently.
+       (while (setq slot (pop slots))
+              (setq slotnum (pop slotnumlist))
+              (cond ((>& slotnum oldlength)
+                     (buildslot))
+                    (  t  (fillbaseslot))))
+       (cond ((\=& 0 hashalias) (puthashalias first*edslot defblock))
+             ( t (puthashalias hashalias defblock)))
+       (cond ((\=& 0 hashfocus) (puthashfocus (gethashfocus olddefblock)
+                                              defblock))
+             ( t (puthashfocus hashfocus defblock)))
+
+       ; Run base hooks attached to the base we are expanding.
+       (and (getbasehooks olddefblock)
+            (setq item valblock)
+            (checkrunhandlebasehooks1 '>expanded *runexpandedhooks*)
+            (setq valblock item))
+       (return valblock)))
+; Fill in an individual slot with the value specified.  If the value is
+;   prefaced by the character "^" then the value should be inherited from
+;   above but there are still predicates and/or IFs to process.
+(dm fillindivslot (none)
+  '(progn
+    (setq slotname (pop slot))
+    ; Find slot number.
+    (and (\=& 0 (setq slotnum (slotnametonumber slotname defblock)))
+        (progn (msg t "CREATE: Undefined slot: " slotname
+                    ", in individual or pattern: " basename)
+               (pearlbreak)))
+    (cond ((\=& 0 (length slot))
+          (msg t "Missing value in: CREATE INDIVIDUAL (or PATTERN) "
+               basename ".  Remaining slots are: " slots t)
+          (pearlbreak))
+         ; If ^, inherit.
+         ((eq (car slot) '^)
+          (setq slot (cdr slot))
+          (inheritvalue defblock))
+         ; Otherwise, construct a new value and insert.
+         ( t (constructvalue)))
+    
+    (handlepossibleadjunctvar)
+
+    ; Store type and value.
+    (putslotvaluetype  slotnum valuetype   valblock)
+    (putslotvalue      slotnum slotvalue   valblock)
+
+    (handlepredicatesandhooks)))
+; Create a new structure of type INDIVIDUAL:  an instance of a
+;    BASE or EXPANDED structure.  Slots are either filled explicitly
+;    or they inherit defaults from above.
+(de createindividual (basename abbrev slots)
+  (or (structurenamep basename)
+      (progn (msg t "CREATE INDIVIDUAL: " basename
+                 " is not the name of a previously declared structure."
+                 t "     Slots are: " slots t)
+            (pearlbreak)))
+  (prog (defblock valblock slotname length slotnum oldvalblock
+                 isa typenum ppset slot predlist slothooklist fcn
+                 slotlocation newvalue result item
+                 slotvalue valuetype)
+
+       ; Find definition and allocate hunk for individual.
+       (setq defblock (eval (defatom basename)))
+       (setq valblock (allocval (setq length (getstructlength defblock))))
+       (puttypetag '*pearlinst* valblock)
+       (cond (*toplevelp* (setq *currenttopcreated* valblock)
+                          (setq *currentpearlstructure* valblock)
+                          (initbothalists valblock)
+                          (setq *currenttopalists* (getbothalists valblock))
+                          ; Include the current environment in 
+                          ;    the variable assoc-list.
+                          (and *blockstack*
+                               (putalist (cdar *blockstack*) valblock))
+                          (setq *toplevelp* nil))
+             ( t (putbothalists *currenttopalists* valblock)))
+
+       (and abbrev
+            (cond ((eq abbrev '*buildabbrev*)
+                   (putabbrev (eval `(newsym ,(getpname defblock))) valblock))
+                  ( t (putabbrev abbrev valblock))))
+       (putdef defblock valblock)
+       (setq oldvalblock (getdefaultinst defblock))
+
+       ; Copy slots from old structure first, then run base hooks.
+       (for slotnum 1 length
+            (copyslot defblock))
+       (and (getbasehooks defblock)
+            (setq item valblock)
+            (checkrunhandlebasehooks1 '<individual *runindividualhooks*)
+            (setq valblock item))
+
+       ; Replace copied values for slots that are actually listed
+       ;    then run base hooks.
+       (while (setq slot (pop slots))
+              (fillindivslot))
+       (and (getbasehooks defblock)
+            (setq item valblock)
+            (checkrunhandlebasehooks1 '>individual *runindividualhooks*)
+            (setq valblock item))
+       (return valblock)))
+; Copy default values, predicates, and hooks for one slot.
+(dm copypatternslot (none)
+  '(progn
+    (putslotvaluetype slotnum 'LOCAL                             valblock)
+    (putslotvalue     slotnum *any*conscell*                     valblock)
+    (putpred          slotnum (getpred      slotnum oldvalblock) valblock)
+    (putslothooks     slotnum (getslothooks slotnum oldvalblock) valblock)))
+; Create a new structure of type PATTERN:  an instance of a BASE or
+;    EXPANDED structure.  Unspecified slots are filled with ?*ANY*.
+(de createpattern (basename abbrev slots)
+  (prog (defblock valblock oldvalblock slotname length slotnum isa
+                 slotlocation slot predlist slothooklist fcn typenum
+                 ppset newvalue result item slotvalue valuetype)
+       (or (structurenamep basename)
+           (progn (msg t "CREATE PATTERN: " basename
+                       " is not the name of a previously declared structure."
+                       t)
+                  (pearlbreak)))
+
+       ; Get definition and allocate hunk for pattern.
+       (setq defblock (eval (defatom basename)))
+       (setq valblock (allocval (setq length (getstructlength defblock))))
+       (setq oldvalblock (getdefaultinst defblock))
+       (puttypetag '*pearlinst* valblock)
+       (cond (*toplevelp* (setq *currenttopcreated* valblock)
+                          (setq *currentpearlstructure* valblock)
+                          (initbothalists valblock)
+                          (setq *currenttopalists* (getbothalists valblock))
+                          ; Include the current environment in 
+                          ;    the variable assoc-list.
+                          (and *blockstack*
+                               (putalist (cdar *blockstack*) valblock))
+                          (setq *toplevelp* nil))
+             ( t (putbothalists *currenttopalists* valblock)))
+
+       (putdef defblock valblock)
+       (and abbrev
+            (cond ((eq abbrev '*buildabbrev*)
+                   (putabbrev (eval `(newsym ,(getpname defblock))) valblock))
+                  ( t (putabbrev abbrev valblock))))
+
+       ; Copy slot values from base and run base hooks on base structure.
+       (for slotnum 1 length
+            (copypatternslot))
+       (and (getbasehooks defblock)
+            (setq item valblock)
+            (checkrunhandlebasehooks1 '<pattern *runpatternhooks*)
+            (setq valblock item))
+
+       ; Fill in new values for any slots listed and run base hooks.
+       (while (setq slot (pop slots))
+              (fillindivslot))
+       (and (getbasehooks defblock)
+            (setq item valblock)
+            (checkrunhandlebasehooks1 '>pattern *runpatternhooks*)
+            (setq valblock item))
+       (return valblock)))
+; Create a new structure of type FUNCTION: a structure with slots
+;    describing the arguments to the function of the same name.
+(de createfunction (fcnname abbrev slots)
+  ; Function must already be defined and be a lambda (expr).
+  (cond ((islambda fcnname)
+        (putprop fcnname t 'functionstruct)
+        (createbase fcnname abbrev slots))
+       ( t  (msg t "CREATE FUNCTION: Only lambdas (exprs) allowed as "
+                 "function structures: " fcnname slots t)
+            (pearlbreak))))
+; vi: set lisp:
diff --git a/usr/src/ucb/lisp/pearl/hash.l b/usr/src/ucb/lisp/pearl/hash.l
new file mode 100644 (file)
index 0000000..4064d25
--- /dev/null
@@ -0,0 +1,690 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;; hash.l ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Functions for hashing, inserting, and fetching items into the
+;    data bases, plus operating on streams.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright (c) 1983 ,  The Regents of the University of California.
+; All rights reserved.  
+; Authors: Joseph Faletti and Michael Deering.
+
+; Find the next item on the CDDR list of the stream that matches the CADR of
+; the stream and return it, also updating the stream.
+(de nextitem (stream)
+  (or (streamp stream)
+      (progn (msg t "NEXTITEM: Not a stream: " stream t)
+            (pearlbreak)))
+  (setq stream (cdr stream))             ; Throw away the *STREAM*.
+  (cond ((eq t (car stream))             ; This means function structure.
+        (prog1 (evalfcn (cdr stream))
+               (rplacd (rplaca stream nil) nil)))
+       ((null (cadr stream)) nil)        ; Test for empty stream
+       ; Stream built by standardfetch.
+       ; To debug or modify this, you must draw a picture of what
+       ;   standardfetch built because of the way it is written.
+       ((not (dtpr (cadr stream)))
+        (prog (item result)
+              (setq item (car stream))
+              (setq *currentpearlstructure* item)
+              (checkrunhandlebasehooks1 '<nextitem *runnextitemhooks*)
+              (while (and (cdr stream)
+                          (or (eq (cadr stream) '*db*)
+                              (not (match item (cadr stream)))))
+                     (rplacd stream (cddr stream)))
+              (setq item (cadr stream))
+              (rplacd stream (cddr stream))
+              (checkrunhandlebasehooks1 '>nextitem *runnextitemhooks*)
+              (return item)))
+       ; Stream built by expandedfetch (or fetcheverywhere).
+       ; To debug or modify this, you must draw a picture of what
+       ;   expandedfetch built because of the way it is written.
+       ((not (dtpr (caadr stream)))
+        (prog (item result)
+              (setq item (car stream))
+              (setq *currentpearlstructure* item)
+              (checkrunhandlebasehooks1 '<nextitem *runnextitemhooks*)
+              (while (and (cdr stream)
+                          (or (eq (caadr stream) '*db*)
+                              (not (expandedmatch item (caadr stream)))))
+                     (or (car (rplaca (cdr stream) (cdadr stream)))
+                         (rplacd stream (cddr stream))))
+              (setq item (caadr stream))
+              (or (not (cdr stream))
+                  (car (rplaca (cdr stream) (cdadr stream)))
+                  (rplacd stream (cddr stream)))
+              (checkrunhandlebasehooks1 '>nextitem *runnextitemhooks*)
+              (return item)))))
+(defmacro hashinfo (slotnum)
+  `(cxr ,slotnum *hashingmarks*))
+
+(defmacro sethashinfo (slotnum value)
+  `(rplacx ,slotnum *hashingmarks* ,value))
+
+(defmacro slotval (slotnum)
+  `(cxr ,slotnum *slotvalues*))
+
+(defmacro storeslot (slotnum value)
+  `(rplacx ,slotnum *slotvalues* ,value))
+
+; If there is anything to hash this slot on, say so and put it in HASHV.
+(defmacro hashablevalue (slotnum item defblock hashinfo)
+  `(not (memq (setq hashv (gethashvalue ,slotnum ,item ,defblock ,hashinfo))
+             *unhashablevalues*)))
+; If this slot is to take part in a hashing combination, (and it is the
+;    second one in :: or ** hashing), then add it to the right hash bucket.
+(dm hashslot (none)
+  '(cond ((\=& 0 hashinfo) nil) ; No hashing to be done
+        ((hashablevalue slotnum item defblock hashinfo) ; Sets HASHV
+         (and (gethash*  hashinfo)
+              (puthash2  unique hashv db2 item))
+;        (and (gethash:  hashinfo)
+;             (puthash1  hashv db1 item))
+         (and (gethash** hashinfo)
+              (cond ((null mark**)
+                     ; First one found.
+                     (setq mark** hashv))
+                    ; Second one found
+                    ((neq t mark**)
+                     (puthash3 unique mark** hashv db2 item)
+                     (setq mark** t))
+                    ; Third or greater found.
+                    (  t  (msg t "HASH: More than two **'s in: "
+                               (getpname defblock) t))))
+;        (and (gethash:: hashinfo)
+;             (cond ((null mark::)
+;                    ; First one found.
+;                    (setq mark:: hashv))
+;                   ; Second one found
+;                   ((neq t mark::)
+;                    (puthash2 mark:: hashv db2 item)
+;                    (setq mark:: t))
+;                   ; Third or greater found.
+;                   (  t  (msg t "HASH: More than two ::'s in: "
+;                              (getpname defblock) t))))
+         (and (gethash*** hashinfo)
+              (cond ((null mark***)
+                     ; First one found.
+                     (setq mark*** (ncons hashv)))
+                    ; Later ones found.
+                    (  t  (tconc mark*** hashv))))
+)))
+; For each of the four ways of hashing, or else just based on the type,
+;    check to see if the pattern can be hashed that way and if so,
+;    RETURN the right hashbucket.  If the previous one can't be done,
+;    try the next one but stop with the first that can be done.
+;    The order is ***, **, ::, &&, *, and :.
+(dm insidestandardfetch (none)
+  '(cond ((prog2
+          (for slotnum 1 length
+               (and (gethash*** (hashinfo slotnum))
+                    (cond ((eq (punbound)
+                               (setq hashv (slotval slotnum)))
+                           (setq mark nil)
+                           (return nil))
+                          ((null mark)
+                           (setq mark (ncons nil))
+                           (tconc mark hashv)
+                           nil)
+                          ( t  (tconc mark hashv)))))
+          mark)
+         (gethashmulti unique (car mark) db2))
+        ((for slotnum 1 length
+              (and (gethash** (hashinfo slotnum))
+                   (cond ((eq (punbound)
+                              (setq hashv (slotval slotnum)))
+                          (return nil))
+                         ((null mark) (setq mark hashv) nil)
+                         ( t (return (gethash3 unique mark hashv db2)))))))
+;       ((for slotnum 1 length
+;             (and (gethash:: (hashinfo slotnum))
+;                  (cond ((eq (punbound)
+;                             (setq hashv (slotval slotnum)))
+;                         (return nil))
+;                        ((null mark) (setq mark hashv) nil)
+;                        ( t (return (gethash2 mark hashv db2)))))))
+        ((and (not (\=& 0 focus))
+              (pboundp (setq hashv (slotval focus))))
+         (recursetoinsidestandardfetch (getslotvalue focus item) db1 db2))
+        ((for slotnum 1 length
+              (and (gethash* (hashinfo slotnum))
+                   (and (pboundp (setq hashv
+                                       (slotval slotnum)))
+                        (return (gethash2 unique hashv db2))))))
+;       ((for slotnum 1 length
+;             (and (gethash: (hashinfo slotnum))
+;                  (and (pboundp (setq hashv
+;                                      (slotval slotnum)))
+;                       (return (gethash1 hashv db1))))))
+        ( t (gethash1 unique db1))))
+(de recursetoinsidestandardfetch (item db1 db2)
+  (let* ((defblock (getdefinition item))
+        (length (getstructlength defblock))
+        (*slotvalues* (makhunk (1+ length)))
+        (*hashingmarks* (makhunk (1+ length)))
+        (unique (getuniquenum defblock))
+        mark hashv focus hashinfo)
+       (setq focus (gethashfocus defblock))
+       (for slotnum 1 length
+            (setq hashinfo (gethashinfo slotnum defblock))
+            (sethashinfo slotnum hashinfo)
+            (or (and (\=& 0 hashinfo)
+                     (not (\=& focus slotnum)))
+                (storeslot slotnum
+                           (gethashvalue slotnum item defblock hashinfo))))
+       (insidestandardfetch)))
+
+; Return a pair consisting of the ITEM and a hash-bucket-list that should
+; have what we are looking for in it.
+(de standardfetch (item &optional (db *db*))
+  (cond ((get (pname item) 'functionstruct)
+        (cons '*stream* (cons t item)))
+       ( t (prog (mark defblock bucket db1 db2 hashv result focus
+                       length hashinfo unique)
+                 (setq defblock (getdefinition item))
+                 (setq *currentpearlstructure* item)
+                 (checkrunhandlebasehooks1 '<fetch *runfetchhooks*)
+                 (setq db1 (getdb1 db))
+                 (setq db2 (getdb2 db))
+                 (setq length (getstructlength defblock))
+                 (setq focus (gethashfocus defblock))
+                 (for slotnum 1 length
+                      (setq hashinfo (gethashinfo slotnum defblock))
+                      (sethashinfo slotnum hashinfo)
+                      (or (and (\=& 0 hashinfo)
+                               (not (\=& focus slotnum)))
+                          (storeslot slotnum
+                                     (gethashvalue slotnum item
+                                                   defblock hashinfo))))
+                 (setq unique (getuniquenum defblock))
+                 (setq bucket (insidestandardfetch))
+                 (checkrunhandlebasehooks1 '>fetch *runfetchhooks*)
+                 (return (cons '*stream* (cons item bucket)))))))
+(aliasdef 'fetch 'standardfetch)
+
+(de expandedfetch (item &optional (db *db*))
+  (cond ((get (pname item) 'functionstruct)
+        (cons '*stream* (cons t item)))
+       ( t (prog (mark defblock defblocklist buckets db1 db2 hashv result
+                       focus length hashinfo)
+                 (setq defblock (getdefinition item))
+                 (setq *currentpearlstructure* item)
+                 (checkrunhandlebasehooks1 '<fetch *runfetchhooks*)
+                 (setq db1 (getdb1 db))
+                 (setq db2 (getdb2 db))
+                 (setq length (getstructlength defblock))
+                 (setq focus (gethashfocus defblock))
+                 (for slotnum 1 length
+                      (setq hashinfo (gethashinfo slotnum defblock))
+                      (sethashinfo slotnum hashinfo)
+                      (or (and (\=& 0 hashinfo)
+                               (not (\=& focus slotnum)))
+                          (storeslot slotnum
+                                     (gethashvalue slotnum item
+                                                   defblock hashinfo))))
+                 (setq defblocklist (cons defblock
+                                          (getexpansionlist defblock)))
+                 ; Note that instead of being one list, buckets is a
+                 ;    list of lists.
+                 (setq buckets
+                       (mapcar
+                        (funl (expandeddefblock)
+                              (let ((unique (getuniquenum expandeddefblock)))
+                                   (insidestandardfetch)))
+                        defblocklist))
+                 (dremove nil buckets)
+                 (checkrunhandlebasehooks1 '>fetch *runfetchhooks*)
+                 (return (cons '*stream* (cons item buckets)))))))
+; Find the object EVERYWHERE it might be: ; (Well, only 1 for each hash method).
+; For each of the four ways of hashing, plus just based on the type,
+;    check to see if the pattern can be hashed that way and if so,
+;    return the right hash bucket. A list of these lists is made.
+;    NIL's are removed in the main function.
+;    The order is ***, **, ::, &&, *, and :.
+(dm insidefetcheverywhere (none)
+  '(let ((bucketlist (ncons nil)))
+       (for slotnum 1 length
+            (and (gethash*** (hashinfo slotnum))
+                 (cond ((eq (punbound)
+                            (setq hashv (slotval slotnum)))
+                        (setq mark nil)
+                        (return nil))
+                       ((null mark) (setq mark (ncons hashv)) nil)
+                       ( t  (tconc mark hashv)))))
+       (and mark
+            (tconc bucketlist
+                   (gethashmulti unique (car mark) db2))
+            (setq mark nil))
+       (for slotnum 1 length
+            (and (gethash** (hashinfo slotnum))
+                 (cond ((eq (punbound)
+                            (setq hashv (slotval slotnum)))
+                        (return nil))
+                       ((null mark) (setq mark hashv) nil)
+                       ( t (tconc bucketlist
+                                  (gethash3 unique mark hashv db2))
+                           (setq mark nil)
+                           (return nil)))))
+       (and (not (\=& 0 focus))
+            (pboundp (setq hashv (slotval focus)))
+            (tconc bucketlist
+                   (recursetoinsidestandardfetch (getslotvalue focus item)
+                                                 db1 db2)))
+       (for slotnum 1 length
+            (and (gethash* (hashinfo slotnum))
+                 (and (pboundp (setq hashv
+                                     (slotval slotnum)))
+                      (tconc bucketlist
+                             (gethash2 unique hashv db2)))))
+       (tconc bucketlist
+              (gethash1 unique db1))
+       (car bucketlist)))
+
+; Return a list consisting of the ITEM and a list of hash-bucket-list
+;   that must have what we are looking for in it if it's there.
+(de fetcheverywhere (item &optional (db *db*))
+  (cond ((get (pname item) 'functionstruct)
+        (cons '*stream* (cons t item)))
+       ( t (prog (mark defblock buckets db1 db2 hashv result focus
+                       length hashinfo unique)
+                 (setq defblock (getdefinition item))
+                 (setq length (getstructlength defblock))
+                 (setq focus (gethashfocus defblock))
+                 (for slotnum 1 length
+                      (setq hashinfo (gethashinfo slotnum defblock))
+                      (sethashinfo slotnum hashinfo)
+                      (or (and (\=& 0 hashinfo)
+                               (not (\=& focus slotnum)))
+                          (storeslot slotnum
+                                     (gethashvalue slotnum item
+                                                   defblock hashinfo))))
+                 (setq *currentpearlstructure* item)
+                 (checkrunhandlebasehooks1 '<fetch *runfetchhooks*)
+                 (setq db1 (getdb1 db))
+                 (setq db2 (getdb2 db))
+                 (setq unique (getuniquenum defblock))
+                 (setq buckets (insidefetcheverywhere))
+                 (dremove nil buckets)
+                 (checkrunhandlebasehooks1 '>fetch *runfetchhooks*)
+                 (return (cons '*stream* (cons item buckets)))))))
+; Discover if a hash alias is to be used.
+(dm noalias (none)
+  '(cond ((>& alias 0)
+         (cond ((gethash< hashinfo)
+                (cond ((gethash> hashinfo) nil) ; < > cancels
+                      ( t t)))
+               ( t nil)))
+        ( t (cond ((gethash< hashinfo) t)
+                  ( t (cond ((gethash> hashinfo) nil) ; < > cancels
+                            ( t t)))))))
+; Get the value that should be hashed for the given slot of ITEM
+;     else return unbound.
+(de gethashvalue (slotnum item defblock hashinfo)
+  (let
+   ((potential (getvalue slotnum item))
+    alias)
+   (cond ((null potential) nil)
+        ((pboundp potential)
+         (let ((potdef (getdefinition potential)))
+              (selectq (getslottype slotnum defblock)
+                       (0 (setq alias (gethashalias potdef))
+                          (cond ((or (noalias)
+                                     (\=& 0 alias))
+                                 (getuniquenum potdef))
+                                ( t
+                                 (setq alias (abs alias))
+                                 (gethashvalue alias potential potdef
+                                               (gethashinfo alias potdef)))))
+                       (1  (getuniquenum potential)) ; Symbol.
+                       (2  potential)                ; Integer.
+                       (3  (punbound))               ; Lisp not hashed.
+                       (otherwise nil))))            ; SetOf not hashed (YET).
+        ( t (punbound)))))
+
+; Fetch the first item matching the pattern.
+(defmacro firstfetch (pattern)
+  `(nextitem (fetch ,pattern)))
+(defmacro fetchcreate (&rest rest)
+  `(fetch (create .,rest)))
+(defmacro inlinefetchcreate (&rest rest)
+  `(fetch (quote ,(create rest))))
+(defmacro inlinecreate (&rest rest)       
+  `(quote ,(create rest)))
+; Build a value to pass to the function for the parameter for this slot.
+(dm fcnslot (none)
+  '(let ((slotv (getvalue slotnum item))
+        (type (getslottype slotnum defblock)))
+       (cond ((eq slotv (punbound))       (punbound))
+             ((and (<& type 4)
+                   (or (not (\=& 0 type))
+                       (not (get (getpname (getdefinition slotv))
+                                 'functionstruct))))        slotv)
+             ((\=& 0 type)
+              (evalfcn slotv))
+             ((\=& 0 (boole 1 3 type))
+              (mapcar (function evalfcn) slotv))
+             ( t slotv))))
+; Evaluate a function structure.
+(de evalfcn (item)
+  (cond ((dtpr item) (mapcar (function evalfcn) item))
+       ((not (get (getpname (getdefinition item)) 'functionstruct)) item)
+       ( t (let* ((defblock (getdefinition item))
+                  (length (getstructlength defblock))
+                  (fcncall (ncons nil))
+                  slotv)
+                 (tconc fcncall (getpname defblock))
+                 (for slotnum 1 length
+                      (tconc fcncall (fcnslot)))
+                 (apply* (caar fcncall) (cdar fcncall))))))
+; A kludge to be removed (with disguisedas) when we implement VIEWS.
+(defmacro getstructorsymnum (strsym) 
+  `(cond ((psymbolp ,strsym) (getuniquenum ,strsym))
+        (  t  (getuniquenum (getdefinition ,strsym)))))
+; (DISGUISEDAS Filler Struct DB) means "Is filler a struct?
+; if there is an item in the data base DB of the form
+;         (STRUCT (<first slot> FILLER) ... )
+; then return it.   If not, return NIL.
+(de disguisedas (filler struct &optional (db *db*))
+  (prog (fillernum bucket db2 item value)
+       (setq db2 (getdb2 db))
+       (setq fillernum (getstructorsymnum filler))
+       (setq bucket (remq '*db*
+                          (gethash2 (getuniquenum struct) fillernum db2)))
+       loop
+       (cond ((null bucket) (return nil))
+             ((and (eq struct (getdefinition (setq item (pop bucket))))
+                   (neq (punbound) (setq value (getvalue 1 item)))
+                   (eq (getstructorsymnum value) fillernum))
+              (return item))
+             ( t (go loop)))))
+
+(de insertbyfocus (focus item db1 db2)
+  (prog (unique mark** mark:: mark*** defblock
+               value hashinfo hashv focusslotnum)
+       (setq defblock (getdefinition focus))
+       (setq unique (getuniquenum defblock))
+       (puthash1 unique db1 item)
+       (and (not (\=& 0 (setq focusslotnum (gethashfocus defblock))))
+            (pboundp (setq value (getvalue focusslotnum focus)))
+            (insertbyfocus value item db1 db2))
+       (for slotnum 1 (getstructlength defblock)
+            (setq hashinfo (gethashinfo slotnum defblock))
+            (cond ((\=& 0 hashinfo) nil)
+                  ((hashablevalue slotnum focus defblock hashinfo) ; Sets HASHV
+                   (and (gethash*  hashinfo)
+                        (puthash2  unique hashv db2 item))
+;                  (and (gethash:  hashinfo)
+;                       (puthash1  hashv db1 item))
+                   (and (gethash** hashinfo)
+                        (cond ((null mark**)
+                               ; First one found.
+                               (setq mark** hashv))
+                              ; Second one found
+                              ((neq t mark**)
+                               (puthash3 unique mark** hashv db2 item)
+                               (setq mark** t))
+                              ; Third or greater found.
+                              (  t  (msg t "HASH: More than two **'s in: "
+                                         (getpname defblock) t))))
+;                  (and (gethash:: hashinfo)
+;                       (cond ((null mark::)
+;                              ; First one found.
+;                              (setq mark:: hashv))
+;                             ; Second one found
+;                             ((neq t mark::)
+;                              (puthash2 mark:: hashv db2 item)
+;                              (setq mark:: t))
+;                             ; Third or greater found.
+;                             (  t  (msg t "HASH: More than two ::'s in: "
+;                                        (getpname defblock) t))))
+                   (and (gethash*** hashinfo)
+                        (cond ((null mark***)
+                               ; First one found.
+                               (setq mark*** (ncons hashv)))
+                              ; Later ones found.
+                              (  t  (tconc mark*** hashv))))
+                   )))
+       (and mark***
+            (puthashmulti unique (car mark***) db2 item))))
+
+; We must put this struct into the data base somewhere,
+; perhaps in several places.
+(de insertdb (item &optional (db *db*))
+  (or item
+      (progn (msg t "Trying to INSERTDB a nil item: " item t)
+            (pearlbreak)))
+  (and (dtpr item)
+       (progn (msg t "Trying to INSERTDB a cons-cell: " item t)
+             (pearlbreak)))
+  (cond ((get (getpname (getdefinition item)) 'functionstruct)
+        (evalfcn item))
+       (  t
+        (prog (unique mark** mark:: mark*** defblock db1 db2
+                      value hashinfo hashv result focus)
+              (setq defblock (getdefinition item))
+              (setq *currentpearlstructure* item)
+              (checkrunhandlebasehooks1 '<insertdb *runinsertdbhooks*)
+              (setq unique (getuniquenum defblock))
+              (setq db1 (getdb1 db))
+              (setq db2 (getdb2 db))
+              (puthash1 unique db1 item)
+              (and (not (\=& 0 (setq focus (gethashfocus defblock))))
+                   (pboundp (setq value (getvalue focus item)))
+                   (insertbyfocus value item db1 db2))
+              
+              (for slotnum 1 (getstructlength defblock)
+                   (setq hashinfo (gethashinfo slotnum defblock))
+                   (hashslot))
+              (and mark***
+                   (puthashmulti unique (car mark***) db2 item))
+              (checkrunhandlebasehooks1 '>insertdb *runinsertdbhooks*)
+              (return item)))))
+; For each way that this slot can be hashed, destructively remove the
+;     item from the correct bucket.  Expects SLOTNUM, DEFBLOCK, ITEM,
+;     MARK**, MARK::, MARK***, HASHV, UNIQUE, DB1, DB2.
+(dm removeslot (none)
+  '(cond ((\=& 0 hashinfo) nil) ; No hashing to be done
+        ((hashablevalue slotnum item defblock hashinfo) ; Sets HASHV
+         (and (gethash*  hashinfo)
+              (delq item (gethash2 unique hashv db2)))
+;        (and (gethash:  hashinfo)
+;             (delq item (gethash1 hashv db1)))
+         (and (gethash** hashinfo)
+              (cond ((null mark**)
+                     (setq mark** hashv))
+                    ((neq t mark**)
+                     (delq item (gethash3 unique mark** hashv db2))
+                     (setq mark** t))
+                    (  t  (msg t "More than two **'s in: "
+                               (getpname defblock) t))))
+;        (and (gethash:: hashinfo)
+;             (cond ((null mark::)
+;                    (setq mark:: hashv))
+;                   ((neq t mark::)
+;                    (delq item (gethash2 mark:: hashv db2))
+;                    (setq mark:: t))
+;                   (  t  (msg t "More than two ::'s in: "
+;                              (getpname defblock) t))))
+          (and (gethash*** hashinfo)
+              (cond ((null mark***)
+                     ; First one found.
+                     (setq mark*** (ncons hashv)))
+                    ; Later ones found.
+                    (  t  (tconc mark*** hashv))))
+)))
+(de removebyfocus (focus item db1 db2)
+  (prog (unique mark** mark:: mark*** defblock hashinfo hashv focusslotnum)
+       (setq defblock (getdefinition focus))
+       (setq unique (getuniquenum defblock))
+       (dremove item (gethash1 unique db1))
+       (and (not (\=& 0 (setq focusslotnum (gethashfocus defblock))))
+            (removebyfocus (getvalue focusslotnum focus) item db1 db2))
+       (for slotnum 1 (getstructlength defblock)
+            (setq hashinfo (gethashinfo slotnum defblock))
+            (cond ((\=& 0 hashinfo) nil)
+                  ((hashablevalue slotnum focus defblock hashinfo) ; Sets HASHV
+                   (and (gethash*  hashinfo)
+                        (delq item (gethash2 unique hashv db2)))
+;                  (and (gethash:  hashinfo)
+;                       (delq item (gethash1 hashv db1)))
+                   (and (gethash** hashinfo)
+                        (cond ((null mark**)
+                               (setq mark** hashv))
+                              ((neq t mark**)
+                               (delq item (gethash3 unique mark** hashv db2))
+                               (setq mark** t))
+                              (  t  (msg t "More than two **'s in: "
+                                         (getpname defblock) t))))
+;                  (and (gethash:: hashinfo)
+;                       (cond ((null mark::)
+;                              (setq mark:: hashv))
+;                             ((neq t mark::)
+;                              (delq item (gethash2 mark:: hashv db2))
+;                              (setq mark:: t))
+;                             (  t  (msg t "More than two ::'s in: "
+;                                      (getpname defblock) t))))
+                   (and (gethash*** hashinfo)
+                        (cond ((null mark***)
+                               ; First one found.
+                               (setq mark*** (ncons hashv)))
+                              ; Later ones found.
+                              (  t  (tconc mark*** hashv))))
+                   )))
+       (and mark***
+            (delq item (gethashmulti unique mark*** db2)))
+       ))
+
+; We may have to remove this struct from several places so look
+;   every place it might have been hashed.
+(de removedb (item &optional (db *db*))
+  (or item
+      (progn (msg t "Trying to REMOVEDB a nil item: " item t)
+            (pearlbreak)))
+  (and (dtpr item)
+       (progn (msg t "Trying to REMOVEDB a cons-cell: " item t)
+             (pearlbreak)))
+  (or (structurep item)
+      (progn (msg t "Trying to REMOVEDB a non-structure: " item t)
+            (pearlbreak)))
+  (cond ((get (getpname (getdefinition item)) 'functionstruct) nil)
+       (  t
+        (prog (unique mark** mark:: mark*** defblock db1 db2
+                      hashinfo hashv result focus)
+              (setq defblock (getdefinition item))
+              (setq *currentpearlstructure* item)
+              (checkrunhandlebasehooks1 '<removedb *runremovedbhooks*)
+              (setq unique (getuniquenum defblock))
+              (or db
+                  (setq db *db*))
+              (setq db1 (getdb1 db))
+              (setq db2 (getdb2 db))
+              (delq item (gethash1 unique db1))
+              (and (not (\=& 0 (setq focus (gethashfocus defblock))))
+                   (removebyfocus (getvalue focus item) item db1 db2))
+              (for slotnum 1 (getstructlength defblock)
+                   (setq hashinfo (gethashinfo slotnum defblock))
+                   (removeslot))
+              (and mark***
+                   (delq item (gethashmulti unique mark*** db2)))
+              (checkrunhandlebasehooks1 '>removedb *runremovedbhooks*)
+              (return item)))))
+; Find the next item on the CDDR list of the stream that is STREQUAL to
+; the CADR of the stream and return it, also updating the stream.
+(de nextequal (stream)
+  (or (streamp stream)
+      (progn (msg t "NEXTEQUAL:  not a stream: " stream t)
+            (pearlbreak)))
+  (setq stream (cdr stream))    ; Throw away the *STREAM*.
+  (cond ((eq t (car stream))    ; This means function structure.
+        (prog1 (evalfcn (cdr stream))
+               (rplacd (rplaca stream nil) nil)))
+       ((null (cadr stream)) nil)   ; Test for empty stream
+       ; Stream built by standardfetch.
+       ; To debug or modify this, you must draw a picture of what
+       ;   standardfetch built because of the way it is written.
+       ((not (dtpr (cadr stream)))
+        (prog (item result)
+              (setq item (car stream))
+              (setq *currentpearlstructure* item)
+              (checkrunhandlebasehooks1 '<nextequal *runnextequalhooks*)
+              (while (and (cdr stream)
+                          (or (eq (cadr stream) '*db*)
+                              (not (strequal item (cadr stream)))))
+                     (rplacd stream (cddr stream)))
+              (cond ((cadr stream)
+                     (setq item (cadr stream)))
+                    ( t (setq item nil)))
+              (rplacd stream (cddr stream))
+              (checkrunhandlebasehooks1 '>nextequal *runnextequalhooks*)
+              (return item)))
+       ; Stream built by expandedfetch (or fetcheverywhere).
+       ; To debug or modify this, you must draw a picture of what
+       ;   expandedfetch built because of the way it is written.
+       ((not (dtpr (caadr stream)))
+        (prog (item result)
+              (setq item (car stream))
+              (setq *currentpearlstructure* item)
+              (checkrunhandlebasehooks1 '<nextequal *runnextequalhooks*)
+              (while (and (cdr stream)
+                          (or (eq (caadr stream) '*db*)
+                              (not (strequal item (caadr stream)))))
+                     (or (car (rplaca (cdr stream) (cdadr stream)))
+                         (rplacd stream (cddr stream))))
+              (cond ((cadr stream)
+                     (setq item (caadr stream)))
+                    ( t (setq item nil)))
+              (or (not (cdr stream))
+                  (car (rplaca (cdr stream) (cdadr stream)))
+                  (rplacd stream (cddr stream)))
+              (checkrunhandlebasehooks1 '>nextequal *runnextequalhooks*)
+              (return item)))))
+; Find out if an EQUAL ITEM is in the DB by using FETCH and then
+;  applying NEXTEQUAL.
+(de indb (item &optional (db *db*))
+  (prog (result newitem answer)
+       (setq *currentpearlstructure* item)
+       (checkrunhandlebasehooks1 '<indb *runindbhooks*)
+       (setq newitem nil)
+       (and (setq answer (nextequal (fetch item db)))
+            (setq newitem (setq item answer)))
+       (checkrunhandlebasehooks1 '>indb *runindbhooks*)
+       (and newitem
+            (neq item newitem)
+            (setq answer item))
+       (return answer)))
+
+; (FOREACH STREAM FCN) applies FCN to each element returned by
+;    NEXTITEM from STREAM.
+(df foreach (l)
+  (let ((stream (eval (car l)))
+       (fcn (cadr l))
+       item)
+       (while (setq item (nextitem stream))
+             (apply* fcn (ncons item)))))
+; Convert a stream to a list of actual matchers.
+(de streamtolist (stream)
+  (let ((result (ncons nil))
+       item)
+       (while (setq item (nextitem stream))
+             (tconc result item))
+       (car result)))
+
+; vi: set lisp:
diff --git a/usr/src/ucb/lisp/pearl/hook.l b/usr/src/ucb/lisp/pearl/hook.l
new file mode 100644 (file)
index 0000000..75a4e5b
--- /dev/null
@@ -0,0 +1,380 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;; hook.l ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Functions for filling in, running and processing the results of
+;    both slot and base hooks.  Also, hidden and visible.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright (c) 1983 ,  The Regents of the University of California.
+; All rights reserved.  
+; Authors: Joseph Faletti and Michael Deering.
+
+; Convert an equal sign followed by an atom into (*SLOT* atom) 
+;    for use in both predicates and hooks.
+(drm \=
+  (lambda ()
+         (let ((nextchar (tyipeek)))
+              (cond ((\=&  9. nextchar) '\=)
+                    ((\=& 10. nextchar) '\=)
+                    ((\=& 13. nextchar) '\=)
+                    ((\=& 32. nextchar) '\=)
+                    ((\=& 41. nextchar) '\=)
+                    ((eqstr (ascii nextchar) '\=)
+                     (readc)
+                     '\=\=)
+                    ( t  (list '*slot* (read)))))))
+; Convert a slotname into a slot number for a particular type of structure.
+(defmacro numberofslot (slotname defblock)
+  `(for slotnum 1 (getstructlength ,defblock)
+       (and (memq ,slotname (getslotname slotnum ,defblock))
+            (return slotnum)))
+  )
+; Fill a predicate or hook (FCN) in with the right things, using
+;         VALUE  for   *  or  >*,
+;        ITEM   for   ** or  >** and to find variables and slotvalues,
+;     and DEFBLOCK to find slotnumbers.
+(de fillin1 (fcn value item defblock)
+  (cond ((null fcn) nil)
+       ((atom fcn) (cond ((eq '** fcn) (list 'quote item))
+                         ((eq '* fcn) (list 'quote value))
+                         ((eq '>** fcn) (list 'quote item))
+                         ((eq '>* fcn) (list 'quote value))
+                         ( t fcn)))
+       ((dtpr fcn)
+        (cond ((eq '*slot* (car fcn))
+               (list 'quote
+                     (getvalue (numberofslot (cadr fcn) defblock)
+                               item)))
+              ((eq '*var* (car fcn))
+               (list 'quote
+                     (valueof (cadr fcn) item)))
+              ((eq '*global* (car fcn))
+               (cadr fcn))
+              ( t (mapcar (funl (x) (fillin1 x value item defblock))
+                          fcn))))
+       (  t  fcn)))
+
+; Fill a two-item predicate or hook (FCN) in with the right things, using
+;         VAL1   for   *
+;         VAL2   for   >*
+;        ITEM1  for   ** and to find variables and slotvalues,
+;        ITEM2  for   >**
+;         RESULT for   ?
+;     and DEFBLOCK to find slotnumbers.
+; Must be made into a LEXPR in UCI Lisp because of number of arguments.
+(de fillin2 (fcn val1 val2 item1 item2 defblock result)
+  (cond ((null fcn) nil)
+       ((atom fcn) (cond ((eq '** fcn)  (list 'quote item1))
+                         ((eq '>** fcn) (list 'quote item2))
+                         ((eq '* fcn)   (list 'quote val1))
+                         ((eq '>* fcn)  (list 'quote val2))
+                         ((eq '\? fcn)  (list 'quote result))
+                         ( t fcn)))
+       ((dtpr fcn)
+        (cond ((eq '*slot* (car fcn))
+               (list 'quote
+                     (getvalue (numberofslot (cadr fcn) defblock)
+                               item1)))
+              ((eq '*var* (car fcn))
+               (list 'quote
+                     (valueof (cadr fcn) item1)))
+              ((eq '*global* (car fcn))
+               (cadr fcn))
+              ( t (mapcar (funl (x) (fillin2 x val1 val2
+                                             item1 item2
+                                             defblock result))
+                          fcn))))
+       ( t   fcn)))
+; If an atom, apply it, else fill it in and evaluate it.
+(defmacro executehook1 (fcn value item defblock)
+  `(cond ((atom ,fcn) (apply* ,fcn (ncons ,value)))
+        (  t  (eval (fillin1 ,fcn ,value ,item ,defblock)))))
+; If an atom, apply it, else fill it in and evaluate it.
+(defmacro executehook2 (fcn val1 val2 item1 item2 defblock result)
+  `(cond ((atom ,fcn) (apply* ,fcn (list ,val1 ,val2)))
+        (  t  (eval (fillin2 ,fcn ,val1 ,val2
+                             ,item1 ,item2 ,defblock ,result)))))
+
+; If slothooks are supposed to be run, run them and check for *done*,
+;    *fail* or *use*, doing the appropriate thing.  Can almost be
+;    used alone but assumes SLOTNUM, ITEM, RESULT, and VALUE.
+(defmacro checkrunhandleslothooks1 (fcn runhooksatom)
+  `(and *runallslothooks*
+       ,runhooksatom
+       (setq result
+             (let ((defblock (getdefinition item))
+                   (alist (getslothooks slotnum item))
+                   (retvalue nil)
+                   pair)
+                  (while (and (not retvalue)
+                              (setq pair (pop alist)))
+                         (and (eq (car pair) ,fcn)
+                              (setq retvalue
+                                    (executehook1 (cdr pair) value
+                                                  item defblock))
+                              (or (and (dtpr retvalue)
+                                       (memq (car retvalue)
+                                             '(*fail* *done* *use*)))
+                                  (setq retvalue nil))))
+                   retvalue))
+       (dtpr result)
+       (selectq (car result)
+                (*done* (and (cdr result)
+                             (return (cadr result)))
+                        (return value))
+                (*fail* (and (cdr result)
+                             (return (cadr result)))
+                        (return '*fail*))
+                (*use* (setq value (cadr result))))))
+
+; *done* and *fail* cause an immediate return.  *use* changes the
+;     value that was going to be used.
+(defmacro handlehookresult (oldval newval)
+  `(and (dtpr ,newval)
+       (selectq (car ,newval)
+                (*done* (and (cdr ,newval)
+                             (return (cadr ,newval)))
+                        (return ,oldval))
+                (*fail* (and (cdr ,newval)
+                             (return (cadr ,newval)))
+                        (return '*fail*))
+                (*use* (setq ,oldval (cadr ,newval))))))
+
+; If slothooks are supposed to be run, run them and check for *done*,
+;    *fail* or *use*, doing the appropriate thing.  Can almost be
+;    used alone but assumes RESULT and ITEM.
+(defmacro checkrunhandlebasehooks1 (fcn runhooksatom)
+  `(and *runallbasehooks*
+       ,runhooksatom
+       (setq result
+             (let ((retvalue nil)
+                   alist
+                   pair
+                   defblock)
+                  (and item
+                       (setq defblock (getdefinition item))
+                       (setq alist (getbasehooks defblock)))
+                  (while (and (not retvalue)
+                              (setq pair (pop alist)))
+                         (and (eq (car pair) ,fcn)
+                              (setq retvalue
+                                    (executehook1 (cdr pair) item
+                                                  item defblock))
+                              (or (and (dtpr retvalue)
+                                       (memq (car retvalue)
+                                             '(*fail* *done* *use*)))
+                                  (setq retvalue nil))))
+                  retvalue))
+       (dtpr result)
+       (selectq (car result)
+                (*done* (and (cdr result)
+                             (return (cadr result)))
+                        (return item))
+                (*fail* (and (cdr result)
+                             (return (cadr result)))
+                        (return '*fail*))
+                (*use* (setq item (cadr result))))))
+
+; If slothooks are supposed to be run, run them.  Assumes SLOTNUM,
+;    ITEM, and VALUE.  This is not a standalone function, since it
+;    does not handle RESULT but rather returns it.
+(defmacro checkandrunslothooks2 (fcn hooks val1 val2 item1 item2)
+  `(let ((defblock (getdefinition ,item1))
+        (retvalue nil)
+        pair)
+       (while (and (not retvalue)
+                   (setq pair (pop ,hooks)))
+              (and (eq (car pair) ,fcn)
+                   (setq retvalue
+                         (executehook2 (cdr pair) ,val1 ,val2
+                                       ,item1 ,item2 defblock result))
+                   (or (and (dtpr retvalue)
+                            (memq (car retvalue)
+                                  '(*fail* *done* *use*)))
+                       (setq retvalue nil))))
+        retvalue))
+
+; Assumes XVAL or YVAL is where you want changes.
+(defmacro doslothooks2< (fcn runhookatom)
+  `(cond ((and *runallslothooks*
+              ,runhookatom)
+         (setq newxval nil)
+         (setq newyval nil)
+         (and (setq xhooks (getslothooks slotnum item1))
+              (setq newxval
+                    (checkandrunslothooks2 ,fcn xhooks xval yval
+                                           item1 item2)))
+         (and (setq yhooks (getslothooks slotnum item2))
+              (setq newyval
+                    (checkandrunslothooks2 ,fcn yhooks yval xval
+                                           item2 item1)))
+         (handlehookresult xval newxval)
+         (handlehookresult yval newyval))))
+
+; Assumes RESULT is where you want changes.
+(defmacro doslothooks2> (fcn runhookatom)
+  `(cond ((and *runallslothooks*
+              ,runhookatom)
+         (setq newxval nil)
+         (setq newyval nil)
+         (and (setq xhooks (getslothooks slotnum item1))
+              (setq newxval
+                    (checkandrunslothooks2 ,fcn xhooks xval yval
+                                           item1 item2)))
+         (and (setq yhooks (getslothooks slotnum item2))
+              (setq newyval
+                    (checkandrunslothooks2 ,fcn yhooks yval xval
+                                           item2 item1)))
+         (handlehookresult result newxval)
+         (handlehookresult result newyval))))
+
+(defmacro checkandrunbasehooks2 (fcn item1 item2)
+  `(let* ((retvalue nil)
+         (defblock (getdefinition ,item1))
+         (alist (getbasehooks defblock))
+         pair)
+        (while (and (not retvalue)
+                    (setq pair (pop alist)))
+               (and (eq (car pair) ,fcn)
+                    (setq retvalue
+                          (executehook2 (cdr pair) ,item1 ,item2
+                                        ,item1 ,item2 defblock result))
+                    (or (and (dtpr retvalue)
+                             (memq (car retvalue)
+                                   '(*fail* *done* *use*)))
+                        (setq retvalue nil))))
+        retvalue))
+
+; Assumes ITEM1 and ITEM2 are where you want changes.
+(defmacro dobasehooks2< (fcn runhookatom)
+  `(cond ((and *runallbasehooks*
+              ,runhookatom)
+         (setq newitem1 (checkandrunbasehooks2 ,fcn item1 item2))
+         (setq newitem2 (checkandrunbasehooks2 ,fcn item2 item1))
+         (handlehookresult item1 newitem1)
+         (handlehookresult item2 newitem2))))
+
+; Assumes RESULT is where you want changes.
+(defmacro dobasehooks2> (fcn runhookatom)
+  `(cond ((and *runallbasehooks*
+              ,runhookatom)
+         (setq newitem1 (checkandrunbasehooks2 ,fcn item1 item2))
+         (setq newitem2 (checkandrunbasehooks2 ,fcn item2 item1))
+         (handlehookresult result newitem1)
+         (handlehookresult result newitem2))))
+
+; Runbasehooks for single items for the user.
+(de runbasehooks1 (fcn item)
+  (and (null item)
+       (progn (msg t "RUNBASEIFS1: Null item given to run hooks on." t)
+             (pearlbreak)))
+  (let* ((retvalue nil)
+        (defblock (getdefinition item))
+        (alist (getbasehooks defblock))
+        pair)
+       (while (and (not retvalue)
+                   (setq pair (pop alist)))
+              (and (eq (car pair) fcn)
+                   (setq retvalue (executehook1 (cdr pair) item item defblock))
+                   (or (and (dtpr retvalue)
+                            (memq (car retvalue) '(*fail* *done* *use*)))
+                       (setq retvalue nil))))
+       retvalue))
+
+; Runbasehooks for two items for the user.
+(de runbasehooks2 (fcn item1 item2 result)
+  (and (null item1)
+       (progn (msg t "RUNBASEIFS2: Null first item given to run hooks on." t)
+             (pearlbreak)))
+  (and (null item2)
+       (progn (msg t "RUNBASEIFS2: Null second item given to run hooks on." t)
+             (pearlbreak)))
+  (let* ((retvalue nil)
+        (defblock (getdefinition item1))
+        (alist (getbasehooks defblock))
+        pair)
+       (while (and (not retvalue)
+                   (setq pair (pop alist)))
+              (and (eq (car pair) fcn)
+                   (setq retvalue
+                         (executehook2 (cdr pair) item1 item2
+                                       item1 item2 defblock result))
+                   (or (and (dtpr retvalue)
+                            (memq (car retvalue) '(*fail* *done* *use*)))
+                       (setq retvalue nil))))
+       retvalue))
+
+; Run slot hooks for the slot named SLOTNAME for one item for the user.
+(de runslothooks1 (fcn item slotname value)
+  (and (null item)
+       (progn (msg t "RUNSLOTIFS1: Null item given to run hooks on." t)
+             (pearlbreak)))
+  (let* ((retvalue nil)
+        (defblock (getdefinition item))
+        (slotnum (numberofslot slotname defblock))
+        (alist (getslothooks slotnum item))
+        pair)
+       (while (and (not retvalue)
+                   (setq pair (pop alist)))
+              (and (eq (car pair) fcn)
+                   (setq retvalue
+                         (executehook1 (cdr pair) value item defblock))
+                   (or (and (dtpr retvalue)
+                            (memq (car retvalue) '(*fail* *done* *use*)))
+                       (setq retvalue nil))))
+       retvalue))
+
+; Run slot hooks for the slot named SLOTNAME for two items for the user.
+; Must be made into a LEXPR in UCI Lisp because of number of arguments.
+(de runslothooks2 (fcn item1 item2 slotname val1 val2 result)
+  (and (null item1)
+       (progn (msg t "RUNSLOTIFS1: Null first item given to run hooks on." t)
+             (pearlbreak)))
+  (and (null item2)
+       (progn (msg t "RUNSLOTIFS1: Null second item given to run hooks on." t)
+             (pearlbreak)))
+  (let* ((retvalue1 nil)
+        (retvalue2 nil)
+        (defblock (getdefinition item1))
+        (slotnum (numberofslot slotname defblock))
+        (alist (getslothooks slotnum item1))
+        pair)
+       (while (and (not retvalue1)
+                   (setq pair (pop alist)))
+              (and (eq (car pair) fcn)
+                   (setq retvalue1
+                         (executehook2 (cdr pair) val1 val2
+                                       item1 item2 defblock result))
+                   (or (and (dtpr retvalue1)
+                            (memq (car retvalue1) '(*fail* *done* *use*)))
+                       (setq retvalue1 nil))))
+       (setq defblock (getdefinition item2))
+       (setq slotnum (numberofslot slotname defblock))
+       (setq alist (getslothooks slotnum item2))
+       (while (and (not retvalue2)
+                   (setq pair (pop alist)))
+              (and (eq (car pair) fcn)
+                   (setq retvalue2
+                         (executehook2 (cdr pair) val2 val1
+                                       item2 item1 defblock result))
+                   (or (and (dtpr retvalue2)
+                            (memq (car retvalue2) '(*fail* *done* *use*)))
+                       (setq retvalue2 nil))))
+       (cons retvalue1 retvalue2)))
+
+; Run command with its associated *run...hooks* atom set to nil
+;    temporarily with a let so that its hooks WON'T be run.
+(defmacro hidden (command)
+  (let ((name (concat '*run (car command) 'hooks*)))
+       `(let ((,name nil))
+            ,command)))
+
+; Run command with its associated *run...hooks* atom set to t
+;    temporarily with a let so that its hooks WILL be run.
+(defmacro visible (command)
+  (let ((name (concat '*run (car command) 'hooks*)))
+       `(let ((,name t))
+            ,command)))
+
+; vi: set lisp:
diff --git a/usr/src/ucb/lisp/pearl/print.l b/usr/src/ucb/lisp/pearl/print.l
new file mode 100644 (file)
index 0000000..36e0659
--- /dev/null
@@ -0,0 +1,396 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;; print.l ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Functions for converting from internal form to a printable form.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; Copyright (c) 1983 ,  The Regents of the University of California.
+; All rights reserved.  
+; Authors: Joseph Faletti and Michael Deering.
+
+; Convert a predicate, which might be a structure, to printable form.
+(de convertpreds (pred)
+  (cond ((or (litatom pred)
+            (dtpr pred)
+            (numberp pred))
+        pred)
+       ((structurep pred) (allform pred))
+       ((definitionp pred) (getpname pred))
+       ( t pred)))
+; Reverse assoc through a list of cons-cells -- look at the CDRs
+;   for value and return the first cons-cell that matches.
+(de revassq (value alist)
+  (while alist  ; is not NIL
+        (and (eq value (cdar alist))
+             (return (car alist)))
+        (setq alist (cdr alist))))
+
+; Convert an ordinal to printable form.
+(defmacro ppsetform (slotval ppset)
+  `(cond ((eq 'int ,ppset) ,slotval)
+        ( t (let ((assqlist (eval (ordatom ,ppset)))
+                  assqresult)
+                 (cond ((setq assqresult (revassq ,slotval assqlist))
+                        (car assqresult))
+                       ((\=& 0 ,slotval) '*zero-ordinal-value*)
+                       ( t  (list ,ppset ,slotval)))))))
+
+; Convert a stream to printable form.
+(defmacro streamform (item)
+  `(cond ((eq t (cadr ,item)) (list '*function-stream:*
+                                   (structureform (cddr ,item))))
+        ((or *fullprint*
+             (not *streamprintlength*))
+         (list '*stream:*
+               (structureform (cadr ,item))
+               (mapcan (funl (struct)
+                             (cond ((eq '*db* struct) nil)
+                                   ( t (ncons (structureform struct)))))
+                       (cddr ,item))))
+        ( t
+         (list
+          '*stream:*
+          (structureform (cadr ,item))
+          (let
+           ((rest (cddr ,item))
+            (result (ncons nil))
+            next)
+           (cond ((dtpr (car rest))
+                  ; stream built by expandedfetch.
+                  (let ((itemnum 1)
+                        bucket)
+                       (while (setq bucket (pop rest))
+                              (mapc
+                               (funl (next)
+                                     (or (eq '*db* next)
+                                         (progn
+                                          (and (>& itemnum *streamprintlength*)
+                                               (progn
+                                                (tconc result '|...|)
+                                                (return (car result))))
+                                          (tconc result (structureform next))
+                                          (setq itemnum (1+ itemnum))
+                                          )))
+                               bucket)
+                              (or rest
+                                  (return (car result))))))
+                 ( t (for itemnum 1 *streamprintlength*
+                          (while (and (setq next (pop rest))
+                                      (eq '*db* next))
+                                 ) ; do nothing
+                          (or next
+                              (return (car result)))
+                          (tconc result (structureform next)))))
+           (and rest
+                (tconc result '|...|))
+           (car result))))))
+; Convert a symbol to printable form.
+(defmacro symbolform (item)
+  `(getsymbolpname ,item))
+
+; Convert an equivalence class list to printable form.
+(defmacro equivclassform (equiv)
+  `(let ((equivclass ,equiv))
+       (mapcan (funl (var)
+                     (cond ((dtpr var) ; a local var
+                            ; filter out variables which are no longer
+                            ; members of the equivalence class
+                            (and (eq (cdr var) equivclass)
+                                 (ncons (list '*var* (car var)))))
+                           ( t ; otherwise a global var
+                               (and (eq (eval var) equivclass)
+                                    (ncons (list '*global* var))))))
+               (cdr equivclass))))
+
+; Convert a definition to printable form.
+(defmacro defform (item)
+  `(cons 'definition-of:
+        (structureform (getdefaultinst ,item))))
+
+; Convert the constant portion of a slot
+(defmacro slotconstform (item typenum ppset)
+  `(selectq ,typenum
+           (0 (or (and *abbrevprint*
+                       (getabbrev ,item))
+                  (structureform ,item)))
+           (1 (symbolform ,item))
+           (2 (ppsetform ,item ,ppset))
+           (3 (allform ,item))
+           (otherwise
+            (let ((newtypenum (- ,typenum 4.)))
+                 (cond ((dtpr ,item)
+                        (mapcar
+                         (funl (singleitem)
+                               (listitemform singleitem newtypenum ,ppset))
+                         ,item))
+                       ; otherwise, in case value is somehow not a list,
+                       ;    do your best.
+                       (t (allform ,item)))))))
+
+; Makes a function out of slotconstform for mapping on a setof slot.
+(de listitemform (item typenum ppset)
+  (slotconstform item typenum ppset))
+
+; Macro version of slotconstform for normal use on a slot's value.
+(defmacro slotitemform (printval)
+  `(let ((item ,printval)
+        (typenum (getslottype slotnum defblock))
+        (ppset (getppset slotnum defblock)))
+       (slotconstform item typenum ppset)))
+
+; Convert a slot from internal form to a list form.
+(dm slotform (none)    ; but assumes SLOTNUM, ITEM, PRINTVAL and PRINTVAR.
+  '(progn
+    (setq printval (getslotvalue slotnum item))
+    (selectq (getslotvaluetype slotnum item)
+            (CONSTANT  (slotitemform printval))
+            (LOCAL     (cond ((eq (punbound) (cdr printval))
+                              (list '*var* (car printval)))
+                             ((equivclassp (cdr printval))
+                              (list (list '*var* (car printval))
+                                    ; Unfortunate kludge to get rid of \'s.
+                                    (ncons 'pearlequals)
+                                    (equivclassform (cdr printval))))
+                             ( t (list (list '*var* (car printval))
+                                       ; Unfortunate kludge to get rid of \'s.
+                                       (ncons 'pearlequals)
+                                       (slotitemform (cdr printval))))))
+            (ADJUNCT   (list (slotitemform (car printval))
+                             (ncons 'pearlequals)
+                             (let ((var (cdr printval)))
+                                  (cond ((dtpr var)
+                                         (list '*var* (car var)))
+                                        ( t (list '*global* var))))))
+            (GLOBAL    (cond ((eq (punbound) (eval printval))
+                              (list '*global* printval))
+                             ((equivclassp (eval printval))
+                              (list (list '*global* printval)
+                                    ; Unfortunate kludge to get rid of \'s.
+                                    (ncons 'pearlequals)
+                                    (equivclassform (eval printval))))
+                             ( t (list (list '*global* printval)
+                                       ; Unfortunate kludge to get rid of \'s.
+                                       (ncons 'pearlequals)
+                                       (slotitemform (eval printval)))))))))
+
+(de structureform (item)
+  (let* ((curlist (ncons nil))
+        (defblock (getdefinition item))
+        (basehooks (getbasehooks defblock))
+        ppset
+        printvar
+        printval)
+       (cond ((and *uniqueprint*
+                   ; if there then return it.
+                   (cdr (assq item *uniqueprintlist*))))
+             ( t (tconc curlist (getpname defblock))
+                 (and *fullprint*
+                      basehooks
+                      (tconc curlist (cons 'if basehooks)))
+                 (and *uniqueprint*
+                      (push (cons item (car curlist))
+                            *uniqueprintlist*))
+                 (for slotnum 1 (getstructlength defblock)
+                      (tconc curlist
+                             (nconc (ncons (car
+                                            (getslotname slotnum defblock)))
+                                    (ncons (slotform))
+                                    (and *fullprint*
+                                         (mapcar (function convertpreds)
+                                                 (getpred slotnum item)))
+                                    (and *fullprint*
+                                         (getslothooks slotnum item)))))
+                 (car curlist)))))
+
+; Convert any combination of PEARL and Lisp items (possibly from internal
+; form) to a printable list structure.
+(de allform (item)
+  (cond ((hunkp item)
+        (selectq (gettypetag item)
+                 (*pearlinst* (structureform item))
+                 (*pearlsymbol* (symbolform item))
+                 (*pearldef* (defform item))
+                 (*pearldb*  (list 'database: (getdbname item)))
+                 (*pearlinactivedb*  (list 'Inactive 'Database))
+                 (otherwise item))) ; arbitrary hunk?.
+       ((streamp item) (streamform item))
+       ((equivclassp item) (equivclassform item))
+       ((atom item) item)
+       ((dtpr item) (cons (allform (car item))
+                          (allform (cdr item))))
+       ; Else return item (arbitrary pieces of core?).
+       ( t item)))
+
+; Convert a PEARL item in full detail and SPRINT the result.
+(de fullform (item)
+  (let ((*fullprint* t)
+       (*abbrevprint* nil)
+       (*uniqueprintlist* nil))
+       (allform item)))
+
+; Convert a PEARL item using abbreviations and SPRINT the result.
+(de abbrevform (item)
+  (let ((*abbrevprint* t)
+       (*fullprint* nil)
+       (*uniqueprintlist* nil))
+       (allform item)))
+
+; Normal function to convert a PEARL item and SPRINT the result.
+(de valform (item)
+  (let ((*fullprint* nil)
+       (*abbrevprint* nil)
+       (*uniqueprintlist* nil))
+       (allform item)))
+
+; Convert any PEARL item using whatever the current settings of 
+;   *abbrevprint*, *fullprint* and *uniqueprint* are,
+;   and SPRINT the result.
+; BUT, don't bother if *quiet* is non-nil.
+(de allprint (item &optional (lmar 0) (rmar 0))
+  (or *quiet*
+      (sprint (allform item) lmar rmar))
+  '*invisible*)
+(de structureprint (item &optional (lmar 0) (rmar 0))
+  (or *quiet*
+      (sprint (structureform item) lmar rmar))
+  '*invisible*)
+(de symbolprint (item &optional (lmar 0) (rmar 0))
+  (or *quiet*
+      (sprint (symbolform item) lmar rmar))
+  '*invisible*)
+(de streamprint (item &optional (lmar 0) (rmar 0))
+  (or *quiet*
+      (sprint (streamform item) lmar rmar))
+  '*invisible*)
+(de fullprint (item &optional (lmar 0) (rmar 0))
+  (or *quiet*
+      (sprint (fullform item) lmar rmar))
+  '*invisible*)
+(de valprint (item &optional (lmar 0) (rmar 0))
+  (or *quiet*
+      (sprint (valform item) lmar rmar))
+  '*invisible*)
+(de abbrevprint (item &optional (lmar 0) (rmar 0))
+  (or *quiet*
+      (sprint (abbrevform item) lmar rmar))
+  '*invisible*)
+; Run some commands but silence any printing it normally does.
+(df quiet (command)
+  (let ((*quiet* t))
+       (eval `(progn ,@command))))
+
+; Print out a data base, printing only buckets that have something in them.
+(de printdb (&optional (db *db*))
+  (let ((db1 (getdb1 db))
+       (db2 (getdb2 db))
+       bucket)
+       (or (databasep db)
+          (progn (msg t "PRINTDB: Argument is not a database." t)
+                 (pearlbreak)))
+       (msg t "DB-Name: " (getdbname db))
+       (msg t "Active: " (getdbactive db))
+       (msg t "Children: " (mapcar (function pname) (getdbchildren db)))
+       (msg t "Parent: " (pname (getdbparent db)))
+       (msg t "DB1:")
+       (and db1
+           (for slotnum 0 (1- *db1size*)
+                (and (setq bucket (remq '*db* (cxr slotnum db1)))
+                     (progn (msg t "    " slotnum ": ")
+                            (pearlprintfn bucket)))))
+       
+       (msg t "DB2:")
+       (and db2
+           (for slotnum 0 (1- *db2size*)
+                (and (setq bucket (remq '*db* (cxr slotnum db2)))
+                     (progn (msg t "    " slotnum ": ")
+                            (pearlprintfn bucket)))))
+       '*invisible*))
+
+; Print complete information on the internal values stored in a structure
+;    and its definition (or a definition and its default instance).
+(de debugprint (item)
+  (let (def name)
+       (cond ((definitionp item)
+             (setq def item)
+             (setq item (getdefaultinst def)))
+            ( t  (setq def (getdefinition item))))
+       (and (setq name (getabbrev item))
+           (msg t "******** " name " ********"))
+       (msg t "Definition:")
+       (msg t "   Unique\#: " (getuniquenum def))
+       (msg "  Length: " (getstructlength def))
+       (msg "  DefaultInst: " (getdefaultinst def))
+       (msg t "   Isa: " (getisa def))
+       (msg t "   Pname: " (getpname def))
+       (msg "  HashAlias: " (gethashalias def))
+       (msg "  ExpansionList: " (getexpansionlist def))
+       (msg t "   BaseIfs: " (getbasehooks def))
+       (msg t "Individual:")
+       (msg "  Abbrev: " (getabbrev item))
+       (msg t "   AList: " (getalist item))
+       (msg "  AListcp: " (getalistcp item))
+       (for slotnum 1 (getstructlength def)
+           (msg t t "***Slotnum " slotnum
+                " : " (getslotname slotnum def))
+           (msg t "Formatinfo: " (getformatinfo slotnum def))
+           (msg "  HashInfo: " (gethashinfo slotnum def))
+           (msg "  Enforce: " (getenforce slotnum def))
+           (msg "  Type: " (getslottype slotnum def))
+           (msg "  PPSet: " (getppset slotnum def))
+           (msg t "ValueType: " (getslotvaluetype slotnum item))
+           (msg "  Internal Value: " (getslotvalue slotnum item))
+           (msg t "Value: " (getvalue slotnum item))
+           (msg "  Preds: " (getpred slotnum item))
+           (msg "  SlotIfs: " (getslothooks slotnum item)))
+       '*invisible*))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; the print functions for use with the top level, msg, and the
+;    trace, break, etc. packages.
+
+; standard trace print should use allform after turning off tracing.
+(de pearltraceprintfn (*traceval*)
+  ; Set the $tracemute flag to t so that tracing won't be done
+  ; inside allform.
+  (let ((\$tracemute t))
+       (print (allform *traceval*))))
+
+; standard showstack print should use allform.
+(de pearlshowstackprintfn (*showstackval*)
+  (print (allform *showstackval*)))
+
+; standard break print should use allform.
+(de pearlbreakprintfn (*breakval*)
+  (print (allform *breakval*)))
+
+; standard fix print should use allform.
+(de pearlfixprintfn (*fixval*)
+  (print (allform *fixval*)))
+
+; msg should allform, unless *invisible*.
+(de msgprintfn (*msgval*)
+  (or (eq '*invisible* *msgval*)
+      (patom (allform *msgval*))))
+
+; printing in a trace-break should allprint.
+(de pearltracebreakprintfn (*printval*)
+  (allprint *printval* 3))
+
+; standard print should allprint.
+(de pearlprintfn (*printval*)
+  (allprint *printval* 3))
+
+; standard dskin print should use allform unless an atom.
+(de dskprintfn (*dskval*)
+  (cond ((atom *dskval*) (patom *dskval*))
+       ( t (print (allform  *dskval*)))))
+
+; vi: set lisp:
diff --git a/usr/src/ucb/lisp/utils/tackon.c b/usr/src/ucb/lisp/utils/tackon.c
new file mode 100644 (file)
index 0000000..b72a542
--- /dev/null
@@ -0,0 +1,114 @@
+#include <stdio.h>
+#include "lconf.h"
+#include "config.h"
+#if ! os_unisoft
+#include <sys/types.h>
+#include <a.out.h>
+/*
+ * $Header: /na/franz/utils/RCS/tackon.c,v 1.4 83/08/22 19:01:17 sklower Exp $
+ *
+ * $Locker:  $
+ *
+ * This program tacks on extra symbols into the symbol table.
+ * someone should write one for system 5.
+ *
+ */
+
+FILE *map;
+int aout;
+#define NEWSIZ 100000
+char newstrb[NEWSIZ];
+
+#endif
+main(argc, argv)
+int argc;
+char *argv[];
+{
+#if ! os_unisoft
+       char sym[50], svalue[50];
+       char *strb,*newstr,*malloc();
+       char *curstr;
+       int value;
+       int cnt;
+       int strsiz;
+       int strcnt;
+       int size;
+       int header_location;
+       struct nlist a;
+       struct exec e;
+
+       argc--, argv++;
+       if (argc == 0 || argc > 2) {
+usage:
+               fprintf(stderr, "usage: tackon map [ a.out ]\n");
+               exit(1);
+       }
+       map = fopen(argv[0], "r");
+       if (map == NULL) {
+               perror(argv[0]);
+               exit(1);
+       }
+       aout = open(argc == 2 ? argv[1] : "a.out", 2);
+       if ((aout < 0) && (argc == 2)) {
+               char Name[256];
+
+               strcpy(Name,argv[1]);
+               strcat(Name,".exe");
+               aout = open(Name,2);
+       }
+       if (aout < 0) {
+               printf(" No object file to tackon or text busy\n");
+               exit(1);
+       }
+       header_location = 0;
+       read(aout,&e, sizeof(e));
+       if (N_BADMAG(e)) {
+               header_location = 512;
+               lseek(aout,512,0);
+               read(aout,&e,sizeof(e));
+               if (N_BADMAG(e)) {
+                       printf("tackon: bad magic number\n");
+                       exit(0);
+               }
+       }
+       /* read current string table into buffer */
+       lseek(aout, N_STROFF(e), 0);    /* seek to string table beginning */
+       read(aout,&strsiz,4);           /* read in string table size      */
+       strb = malloc(strsiz);
+       read(aout,strb,strsiz);         /* read in string table */
+       lseek(aout, N_STROFF(e), 0);    /* now write at end of symbols    */
+       cnt = 0;
+       strcnt = 4 + strsiz;
+       curstr = newstrb;               /* point to new string buffer */
+       for (;;) {
+               if (fgets(sym, 50, map) == NULL)
+                       break;
+               sym[size=strlen(sym)-1] = 0;
+               if (fgets(svalue, 50, map) == NULL) {
+                       fprintf(stderr, "missing value\n");
+                       break;
+               }
+               strcpy(curstr,sym);
+               sscanf(svalue, "%x", &a.n_value);
+               a.n_un.n_strx = strcnt;
+               a.n_type = N_EXT|N_TEXT;
+               write(aout, &a, sizeof (a));
+               curstr += size+1;
+               strcnt += size+1;
+               cnt++;
+               if( curstr >= &newstrb[NEWSIZ])
+               {
+                       printf(" Tackon; string buffer overflow \n");
+                       exit(1);
+               }
+       }
+       write(aout, &strcnt, 4);        /* new character count */
+       write(aout, strb, strsiz);      /* write out old string table */
+       write(aout, newstrb, strcnt - ( 4 + strsiz));
+       lseek(aout, header_location, 0);
+       e.a_syms += cnt*sizeof(struct nlist);
+       lseek(aout, header_location, 0);
+       write(aout, &e, sizeof (e));
+       exit(0);
+#endif
+}