``Bootstraping LISP'' means ``Creating a pure STD-LISP interpreter from
scratch''. Here is how to do it:
-
Put all the files with extension ".l'' into the same directory.
Put also the C programs cr1.c cr2.c crc.c
cri.c size.c crfile.h into the same directory.
Each of these C programs will create a part of the C source,
those
which will later be compiled by a C compiler and presumably
will be linked to get the actual executable program.
- cr1
- Will create lisp1.c the part of the LISP system
that contains the static declarations.
- cr2
- Will create lisp2.c. lisp2.c is the
source of
all the LISP system functions, the memory manager,
the garbage collector, the I/O routines etc.
Unless these definitions are not changed you do
not have to run cr2 more than once even if you
later perform a LISP C compilation
of any LISP program.
(Please note that this is not so for lisp1.c
when you later perform a LISP code compilation than
cr1 has to be fired again to reproduce
lisp1.c.
- crc
- Actually this program and the below described program
will only be used if you will compile a LISP program
that you have written. Details will be explained
in the section entitled ``Compiling a LISP code''.
For the time being just know that this program will
attack the output of the LISP C
compiler and produce a true C source that will be
C compilable.
- cri
- Just as crc this program is also used only
if a user written LISP code is compiled. It produces
a LISP initialization file, in which the
non-compilable, user defined LISP expressions are stored.
(e.g. quoted lists, strings, atom names).
-
Change the directory information in the crfile.h file.
We hear you groaning, but this was necessary, again, to
keep true portability, since systems with different operating
system have different directory and file access strings.
(The trivial example is UNIX versus DOS, one has a slash, the
other has a backslash for directories)
-
If necessary edit the file flags.lIn this file you have
various compiler flags for the C compilation. They are explained below:
- TRACEABLE
- If you perform a traceable and/or redefinable
code generation (see the relevant section
on this topic) for user defined functions,
this C flag if zero, tells the C compiler
to omit the traceability or redefinability.
So, the value of this flag is only important
if you perform a LISP C compilation.
- DSTACK
- Of course any LISP has to have a stack, that
is for sure. The DSTACK C flag stands for
`Dynamic-STACK' depending on which the stack
is created in the static data area or
alternatively allocated at run time as a dynamic
memory.
- BITF
- If this flag is non-zero then the code generated
will make use of the bit-sub field concept
of C. If the flag is set to zero no such code
will be generated.
The bit fields come into account in the
tag of a dotted pair, where various informations
have to be hold about that dotted pair
(e.g. one bit is for garbage collection marking).
It is cute and elegant to use in this case
bit-fields, but unfortunately some compilers
generate a terrible code for bit-field accesses.
(e.g. some of them perform a number of shift
right operations to get the desired bit to the
least significant bit position and then test
it, which is awful!).
But another alternative
is to use just a byte and mask the bits of it.
Then setting will correspond to a bitwise OR,
and the testing will correspond to bitwise AND
operation among the tested byte containing the
tested bit and the selection mask byte.
- TURBOC
- If you are using Borland's Turbo C compiler
this file will serve for better code generation.
- IBMPC
- If you are working on an IBM-PC or compatible,
then the higher ascii codes are set in a specific
manner, if this flag is non-zero the generated
C code of the LISP interpreter will make use
of these ascii codes.
Furthermore the IBM-PC is
using the 80x86 P-chip which allows pointers
to sit at addresses that are not zero (modulo 4).
The code makes use of this (non-portable) feature
if the flag IBMPC is set to 1. If you don't have
an 80x86 or if you get errors like
(bus-error, segmentation fault) turn this flag to
zero.
-
Compile all the C files, that you have copied.
-
Execute the size program you have just compiled.
This program will propose a value for the constant PAGESIZEThat constant lives in the file types.lSet in this file
#define PAGESIZE to an integer multiple of the proposed value.
data structures may have different sizes on different C
compilers, because of the underlying hardware. Therefore it is
necessary to determine how your compiler acts. We need this
information because this LISP implementation does not simply use
malloc or calloc when it has to create a LISP data
object, for further details see the chapter on ``The Dynamic
Structure''.
-
Execute cr1 and cr2 in order to generate lisp1.c \
and lisp2.c respectively.
-
Compile lisp1.c and lisp2.c with the C compiler.
- Link them,
with the appropriate libraries in order to obtain an executable
program which is your STD-LISP interpreter.
what the libraries will be is something system dependent, so
since you got your hands on a C compiler, we have to assume that
you are fully capable of creating an executable code after
a C compilation.