Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

lisp

9 views
Skip to first unread message

David D Jansen

unread,
Jan 14, 1992, 5:04:42 PM1/14/92
to
The following is a lisp compiler written several years back for the HP28S.
I have just ported it to the HP48 (made it downloadable). I take no credit
for the program (though I wish I could). Try it, it's great!

Dave
-----
Well, here it is: Crwth-Lisp 3.2!

The impact Crwth-Lisp 3.1 made on the net was beyond my wildest dreams.

Suggestions, hints, bug-reports, flames and loveletters are welcome (though
I hope I will receive no bug-reports!).

Changes since Crwth-Lisp 3.1 are listed in the preface of the manual.

/Crwth
-----
Olle Gallmo (Crwth)
Email: cr...@kuling.UU.SE
Real: Skyttevagen 68, 181 46 Lidingo, Sweden

Cut Here 8<----------------------------------------------------------------------
%%HP: T(3)A(R)F(.);
DIR
@ Crwth-Lisp 3.2
@ A Lisp Compiler for the HP48SX
@ by Olle Gallmo (Crwth) 1988
@ -----
LISP @ ( L-expr --- Value )
\<< @ Compile an L-expr to a program block
COMP \->PROG STR\-> EVAL @ and evaluate it
\>> @
@ -----
COMP @ ( L-expr --- String )
\<< @ Compile an L-expr to a string of
IF DUP TYPE 5 SAME THEN @ HP48-instructions
CLIST @ Lists
ELSE @
IF DUP TYPE 6 SAME THEN @ Atoms
CATOM @
ELSE @
IF DUP TYPE 2 SAME THEN @ Strings
34 CHR SWAP OVER + + @ A string in a string!
ELSE @
\->STR @ Others
END @
END @
END @
" " + @
\>> @
@ -----
CLIST @ ( List --- String )
\<< @ Compile a list
IF DUP {} SAME THEN @ An empty list compiles to itself
DROP "{}" @
ELSE @
DUP REST SWAP 1 GET @ Get tail and head
IF SPA OVER POS THEN @ If Functor is a special form
SPB SPA ROT POS GET EVAL @ compile special form
ELSE @
CFUN @ Else compile a normal funcall
END @
END @
\>> @
@ -----
CATOM @ ( Atom --- String )
\<< @ Compile an atom
IF MACA OVER POS DUP THEN @ If the atom is defined as a macro
SWAP DROP MACB SWAP GET @ get the corresponding string
ELSE @
DROP \->STR 2 OVER SIZE 1 - SUB @ Else Convert to string and delete the 's
END @
\>> @
@ -----
CFUN @ ( Arglist Functor --- String )
\<< @ Compile a funcall
COMP SWAP @ Compile the functor
IF DUP SIZE THEN @ If funcall has arguments
CSEQ SWAP + @ compile them first and add the functor
ELSE @
DROP @ Else just return the functor
END @
\>> @
@ -----
CSEQ @ ( Arglist --- String )
\<< @ Compile a sequence of funcalls
"" 1 3 PICK SIZE FOR i @ (for instance the body of a DEFUN,
OVER i GET COMP + @ LET or COND)
NEXT @
SWAP DROP @
\>> @
@ -----
SPQ @ ( Arglist --- String )
\<< @ Compile special form QUOTE
1 GET \->STR @
\>> @
@ -----
SPDEF @ ( Arglist --- String )
\<< @ Compile special form DEFUN
DUP CDEF \->PROG STR\-> @ Compile the definition
SWAP 1 GET STO "1" @ Store in a variable
\>> @
@ -----
SPMAC @ ( Arglist --- String )
\<< @ Compile special form DEFMAC
DUP CDEF MACB + 'MACB' STO @ Compile the definition into MACB
1 GET MACA + 'MACA' STO "1" @ and store the macro-name in MACA
\>> @
@
CDEF @ (Arglist --- String )
\<< @ Compile a definition (DEFUN or DEFMAC)
DUP 3 OVER SIZE SUB CSEQ @ Compile the body
SWAP 2 GET @ Get the parameter-list
IF DUP SIZE THEN @ If function takes arguments
CSEQ "\-> " SWAP + @ create local variables for them
SWAP \->PROG + @ and add the compiled body
ELSE @ Else
DROP @ just leave the compiled body
END @
\>> @
@ -----
SPLET @ ( Arglist --- String )
\<< @ Compile special form LET
DUP REST CSEQ \->PROG @ Compile the body
SWAP 1 GET @ Get declarations
"" 1 3 PICK SIZE FOR i @ Compile values of the local variables
OVER i GET 2 GET COMP + @
NEXT @
"\-> " + @
1 3 PICK SIZE FOR i @ Create corresponding HP28-code
OVER i GET 1 GET COMP + @ local variables
NEXT @
SWAP DROP SWAP + @ and add the compiled body
\>> @
@ -----
SPCOND @ ( Arglist --- String )
\<< @ Compile special form COND
IF DUP SIZE 1 SAME THEN @ If only one test left
1 GET DUP 1 GET COMP @
IF DUP "1 " SAME THEN @ If it is an 'else'
DROP REST CSEQ @ just compile
ELSE @ Else
"IF " SWAP + "THEN " + @ Create an IF-THEN-END
SWAP REST CSEQ + "END " + @
END @
ELSE @ Else
"IF " OVER 1 GET 1 GET COMP + @ Create an IF-THEN-ELSE-SPCOND-END
"THEN " + @
OVER 1 GET REST CSEQ + @
"ELSE " + @
SWAP REST SPCOND + @
"END " + @
END @
\>> @
@ -----
SPA @ List of special forms
{ QUOTE DEFUN DEFMAC LET COND } @
@ -----
SPB @ List of corresponding compiling words
{ SPQ SPDEF SPMAC SPLET SPCOND } @
@ -----
MACA @ List of macros
{ T NIL } @
@ -----
MACB @ List of corresponding strings
{ "1" "0" } @
@ -----
\->PROG @ ( String --- String )
\<< @ Put program delimiters on both sides
"\<< " SWAP + "\>> " + @ of a HP28-code string
\>> @
@ -----
REST @ Get the tail of a list
\<< @
2 OVER SIZE SUB @
\>> @
@ -----
END

--
I am a self-made man who worships his creator.
_______________________________________________________________________________
Dave Jansen | INTERNET: eldo...@en.ecn.purdue.edu
Electrical Engineering | BITNET: eldorado%ea.ecn.purdue.edu@purccvm

David D Jansen

unread,
Jan 14, 1992, 5:05:42 PM1/14/92
to
This is the documentation for the lisp compiler.

Dave
-----

Crwth-Lisp 3.2
--------------

A Lisp compiler for the HP28S

by

Olle Gallmo (Crwth)

September 1988

Preface (Changes since version 3.1)
-----------------------------------

DEFMAC has been added. You can now define macros in Crwth-Lisp.

The bug in COND has been corrected. In Crwth-Lisp 3.1 you could not have a
sequence of funcalls in the consequence-part of a COND.

COND returns nothing if none of the tests were true. Crwth-Lisp 3.1 returned
NIL. The reason Crwth-Lisp 3.1 did this was that I wanted COND always to
return something, but I can't be sure of that anyway since it may call a
HP28-code function that doesn't return anything.

The HP28C-patch has been removed from the manual, since the compiler needs
approx. 1.4 Kb and won't be any fun on a HP28C.

1. Introduction
---------------

The goal I wanted to achieve was to create a Lisp look-alike language for the
HP28. I wanted it to be as small as possible and efficient enough to be more
than a toy.

First I made a small interpreter with which I could call most of the HP28's
builtin functions as a Lisp expression (L-expr), but soon I discovered that
a compiler would be easier to write and of course more efficient.

What I have so far is a compiler that gives me *almost* total control over the
HP28 and produces *almost* optimal HP28-code.

2. Description
--------------

Crwth-Lisp differs somewhat from conventional Lisps. The main differences
are the syntax, the representation of lists and the truthvalues.

A list is equivalent to the HP28's lists, i.e. a list is denoted by
curly brackets and there are no conses or dotted pairs.

NIL and {} are NOT equivalent!

{} is an empty list but NOT a truthvalue.

NIL is a truthvalue, equivalent to HP28's 0 (zero), NOT to the
empty list.

The atom T is compiled to HP28's 1 (one).

I have chosen this representation of truthvalues because I want it to be easy
to use HP28's predicates from Lisp and vice versa without having to convert
between the different truthvalues.

The HP28 screams "Syntax Error" if you try to push a list on the stack con-
taining any atom in the BRANCH menu. Thus it is not possible to call these
HP28-functions directly from Crwth-Lisp.

The compiler is very small. It only has to know about a few special forms. It
is not necessary to define FIRST, REST, CONCAT and so forth since that can be
done in Crwth-Lisp itself by calling the HP28's builtin functions.

The special forms currently defined in the compiler are QUOTE, DEFUN, DEFMAC,
LET and COND.

3. The compiler
---------------

LISP - Compiles an L-expr to a program block and evaluates it.
COMP - Compiles an L-expr to a string of HP28-instructions.
CLIST - Compiles a list.
CATOM - Compiles an atom.
CFUN - Compiles a funcall.
CSEQ - Compiles a sequence of funcalls.
SPQ - Compiles special form QUOTE.
SPDEF - Compiles special form DEFUN.
SPMAC - Compiles special form DEFMAC.
CDEF - Compiles a DEFUN or a DEFMAC without storing the result.
SPLET - Compiles special form LET.
SPCOND - Compiles special form COND.
SPA - A list containing the Lisp names of the special forms.
SPB - A list containing the compiler function that compiles a special form.
MACA - A list containing the macro names.
MACB - A list containing the macro's definitions.
->PROG - Puts program block delimiters around a HP28-code string.
REST - Returns the tail of a list.

LISP is the only function you need to know anything about. It takes an L-expr
as argument. If the L-expr is a DEFUN the function will be compiled to HP28-
code and stored under a variable. If the L-expr is a DEFMAC the function will
be compiled and stored in the MACA and MACB variables (see section 6). If the
L-expr is something else, Crwth-Lisp will act like an interpreter, i.e. it
will compile the L-expr to HP28-code and evaluate it immediately.

4. Factorial -- an example
--------------------------

Push the definition of factorial on the stack.

{DEFUN FAC {X}
{COND {{== X 0} 1}
{T {* X {FAC {- X 1}}}}}}

Now call LISP. After a while FAC will appear as a new variable in the menu,
and LISP returned a 1 (which is the same as T, remember?).

Visit FAC to see what it looks like.

<< -> X
<<
IF X 0 == THEN
1
ELSE
X X 1 - FAC *
END
>>
>>

If you were to write a factorial in HP28-code you probably wouldn't name the
argument -- you would rather operate directly on the stack (at least I would).
One thing in common of all compiled Crwth-Lisp functions is that they always
take the arguments they need from the stack and stores them in local variables
instead of operating on the stack (though it is possible to operate on the
stack in Crwth-Lisp, it is what I would call ugly programming).

Now, if you want to calculate 5! you can do it in two ways:

As a HP28-function, by pushing 5 on the stack and then press FAC.

As a Crwth-Lisp call, by pushing {FAC 5} on the stack and
then press LISP.

The latter will take somewhat longer since {FAC 5} will be compiled to HP28-
code before execution.

5. Local variables
------------------

You can create local variables in Crwth-Lisp with the special form LET. It be-
haves as the Common-Lisp LET.

Ex. {DEFUN FOO {X}
{LET {{A 5} ; A and B are local variables.
{B 42}}
{* {+ X B} A}}}


The compiled code will use HP28's way of creating local variables:

<< -> X
<< 5 42 -> A B
<< X B + A *
>>
>>
>>

6. Macros
---------

Equality is called '==' in HP28-code, but in Crwth-Lisp you would rather call
it 'EQ'. You could of course define EQ with a DEFUN as:

{DEFUN EQ {X Y} {== X Y}}

but this would make the HP28-code rather slow if you use EQ alot and whenever
you move your compiled super-duper-program you'll have to take the small EQ-
definition with you or it won't be found when EQ is called.

Lets define EQ as a macro instead (with DEFMAC):

{DEFMAC EQ {X Y} {== X Y}}

EQ won't be stored as a function but as a macro. The name EQ will be added to
the MACA-list, and the compiled code will be added as a string to the MACB-
list.

Now, when you compile a program that calls EQ, the funcall will be substituted
by the code in the MACB-list.

Dirty hint: You can fool the compiler and define EQ as {DEFMAC EQ {} {==}}
instead, which will inhibit the naming of the parameters.

Very short functions or HP28-code functions that you would like to call
something else in Crwth-Lisp, could preferably be defined as macro's.

If you define a macro in the same directory as the compiler, the compiler's
MACA and MACB will be extended. The only way to get rid of a macro definition
would be to edit the MACA- and MACB-list. But if you define your macros in
a subdirectory instead, the extended MACA- and MACB-lists will be stored in
the subdirectory. Then you can just purge them when you want to get rid of your
macro's -- The global MACA- and MACB-lists will be untouched in the compiler-
directory.

Warning: Don't purge the MACA- or MACB-lists from the compiler directory -- the
compiler needs them!

7. Comments
-----------

It is a good idea to create your Crwth-Lisp programs in a subdirectory
to the compiler -- you don't want to accidently damage the compiler.
I created a LISP-directory for the compiler which has a SRC- and a BIN-
subdirectory.

If a Crwth-Lisp function calls a HP28-code procedure that doesn't return
anything (DISP for instance) the Crwth-Lisp function won't return anything
either.

Remember to treat NIL as a truthvalue and a truthvalue ONLY!

This is an overview, not a complete manual.

Crwth (pronounced 'croth') is an old celtic lyre.

Have fun!
--

Olle Gallmo (Crwth)
Email: cr...@kuling.UU.SE
Real: Skyttevagen 68, 181 46 Lidingo, Sweden


==================================================
(end)

0 new messages