home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 4
/
FreshFish_May-June1994.bin
/
bbs
/
may94
/
util
/
edit
/
jade.lha
/
Jade
/
lisp
/
compiler.jl
< prev
next >
Wrap
Lisp/Scheme
|
1994-04-16
|
28KB
|
884 lines
;;;; compiler.jl -- Simple compiler for Lisp files/forms
;;; Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
;;; This file is part of Jade.
;;; Jade is free software; you can redistribute it and/or modify it
;;; under the terms of the GNU General Public License as published by
;;; the Free Software Foundation; either version 2, or (at your option)
;;; any later version.
;;; Jade is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;;; GNU General Public License for more details.
;;; You should have received a copy of the GNU General Public License
;;; along with Jade; see the file COPYING. If not, write to
;;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
;;;
;;; The opcode of instructions which take an argument is:
;;; bits:
;;; 0->2 argument/type, 0->5 = literal, 6 = next byte, 7 = next 2 bytes.
;;; 3->7 opcode.
;;;
;;; If an instruction needs extra bytes only the bottom 7 bits of each are
;;; used, the top bit is always set. (This is so no \0 bytes end up in the
;;; string.)
;;;
;;; When two extra bytes are used the high 7 bits are stored first, then the
;;; low seven bits.
;;;
(provide 'compiler)
;; Options
(defvar comp-eval-constants-p t
"When t any references to variables which are marked as being constant (ie,
by `defconst' or `set-constant-variable') are evaluated at compile time.")
(defvar comp-write-docs-p nil
"When t all doc-strings are appended to the doc file and replaced with
their position in that file.")
;; Opcodes
(defconst op-call 0x08) ; call (stk[n] stk[n-1] ... stk[0])
;pops n values, replacing the
;function with the result.
(defconst op-push 0x10) ; pushes constant # n
(defconst op-vrefc 0x18) ; pushes val of symbol n (in c-v)
(defconst op-vsetc 0x20) ; sets symbol n (in c-v) to stk[0],
;then pops the stack.
(defconst op-list 0x28) ; makes top n items into a list
(defconst op-bind 0x30) ; bind constant n to stk[0], pops stk
(defconst op-last-with-args 0x37)
(defconst op-vref 0x40) ; replace symbol with it's value
(defconst op-vset 0x41) ; set (sym)stk[0]=stk[1], pops both
(defconst op-fref 0x42) ; similar to vref/vset, but for
(defconst op-fset 0x43) ;function value.
(defconst op-init-bind 0x44) ; initialise a new set of bindings
(defconst op-unbind 0x45) ; unbind all bindings in the top set
(defconst op-dup 0x46) ; duplicate top of stack
(defconst op-swap 0x47) ; swap top two values on stack
(defconst op-pop 0x48) ; pops the stack
(defconst op-nil 0x49) ; pushes nil
(defconst op-t 0x4a) ; pushes t
(defconst op-cons 0x4b)
(defconst op-car 0x4c)
(defconst op-cdr 0x4d)
(defconst op-rplaca 0x4e)
(defconst op-rplacd 0x4f)
(defconst op-nth 0x50)
(defconst op-nthcdr 0x51)
(defconst op-aset 0x52)
(defconst op-aref 0x53)
(defconst op-length 0x54)
(defconst op-eval 0x55)
(defconst op-plus-2 0x56) ; The `-2' on the end means that it
(defconst op-negate 0x57) ;only works on 2 arguments.
(defconst op-minus-2 0x58)
(defconst op-product-2 0x59)
(defconst op-divide-2 0x5a)
(defconst op-mod-2 0x5b)
(defconst op-bit-not 0x5c)
(defconst op-not 0x5d)
(defconst op-bit-or-2 0x5e)
(defconst op-bit-and-2 0x5f)
(defconst op-equal 0x60)
(defconst op-eq 0x61)
(defconst op-num-eq 0x62)
(defconst op-num-noteq 0x63)
(defconst op-gtthan 0x64)
(defconst op-gethan 0x65)
(defconst op-ltthan 0x66)
(defconst op-lethan 0x67)
(defconst op-inc 0x68)
(defconst op-dec 0x69)
(defconst op-lsh 0x6a)
(defconst op-zerop 0x6b)
(defconst op-null 0x6c)
(defconst op-atom 0x6d)
(defconst op-consp 0x6e)
(defconst op-listp 0x6f)
(defconst op-numberp 0x70)
(defconst op-stringp 0x71)
(defconst op-vectorp 0x72)
(defconst op-catch-kludge 0x73)
(defconst op-throw 0x74)
(defconst op-unwind-pro 0x75)
(defconst op-un-unwind-pro 0x76)
(defconst op-fboundp 0x77)
(defconst op-boundp 0x78)
(defconst op-symbolp 0x79)
(defconst op-get 0x7a)
(defconst op-put 0x7b)
(defconst op-error-pro 0x7c)
(defconst op-signal 0x7d)
(defconst op-set-current-buffer 0xb0)
(defconst op-swap-buffer 0xb1) ; switch to buffer stk[0], stk[0]
;becomes old buffer.
(defconst op-current-buffer 0xb2)
(defconst op-bufferp 0xb3)
(defconst op-mark-p 0xb4)
(defconst op-windowp 0xb5)
(defconst op-swap-window 0xb6)
(defconst op-last-before-jmps 0xfa)
;; All jmps take two-byte arguments
(defconst op-jmp 0xfb) ; jmp to x
(defconst op-jmp-nil 0xfc) ; pop the stack, if nil, jmp x
(defconst op-jmp-t 0xfd) ; pop the stack, if t, jmp x
(defconst op-jmp-nil-else-pop 0xfe) ; if stk[0] nil, jmp x, else pop
(defconst op-jmp-t-else-pop 0xff) ; if stk[0] t, jmp x, else pop
(defconst comp-max-1-byte-arg 5) ; max arg held in 1-byte instruction
(defconst comp-max-2-byte-arg 0x7f) ; max arg held in 2-byte instruction
(defconst comp-max-3-byte-arg 0x3fff) ; max arg help in 3-byte instruction
(defvar comp-constant-alist nil) ; list of (VALUE . INDEX)
(defvar comp-constant-index 0) ; next free constant index number
(defvar comp-current-stack 0) ; current stack requirement
(defvar comp-max-stack 0) ; highest possible stack
(defvar comp-output nil) ; list of (BYTE . INDEX)
(defvar comp-output-pc 0) ; INDEX of next byte
(defvar comp-macro-env nil) ; alist of (NAME . MACRO-DEF)
(defun compile-file (file-name)
"(compile-file FILE-NAME)
Compiles the file of jade-lisp code FILE-NAME into a new file called
`(concat FILE-NAME ?c)' (ie, `foo.jl' => `foo.jlc')."
(let*
(src-file dst-file form comp-macro-env)
(when (and (setq src-file (open file-name "r"))
(setq dst-file (open (concat file-name ?c) "w")))
(error-protect
(unwind-protect
(progn
(title-now (concat "Compiling file " file-name "..."))
(while (not (file-eof-p src-file))
(when (setq form (comp-compile-file-form (read src-file)))
(print form dst-file)
(write dst-file ?\n))))
(close dst-file)
(close src-file))
(error
;; Be sure to remove any partially written dst-file. Also, signal
;; the error again so that the user sees it.
(let
((fname (concat file-name ?c)))
(when (file-exists-p fname)
(delete-file fname)))
(funcall 'signal (car error-info) (cdr error-info))))
t)))
(defun compile-directory (dir-name &optional force-p)
"(compile-directory DIRECTORY-NAME [FORCE-P])
Compiles all jade-lisp files in the directory DIRECTORY-NAME whose object
files are either older than their source file or don't exist. If FORCE-P
is non-nil every lisp file is recompiled."
(let
((dir (directory-files dir-name)))
(while (consp dir)
(when (regexp-match "\\.jl$" (car dir))
(let*
((file (file-concat dir-name (car dir)))
(cfile (concat file ?c)))
(when (file-newer-than-file-p file cfile)
(compile-file file))))
(setq dir (cdr dir)))
t))
(defun compile-lisp-lib (&optional force-p)
"(compile-lisp-lib [FORCE-P])
Recompile all out of date files in the lisp library directory. If FORCE-P
is non-nil it's as though all files were out of date.
This makes sure that all doc strings are written to their special file."
(let
((comp-write-docs-p t))
(compile-directory lisp-lib-dir force-p)))
(put 'compile-error 'error-message "Compilation mishap")
(defun comp-error (&rest data)
(signal 'compile-error data))
(defun comp-compile-file-form (form)
(if (not (consp form))
form
(let
((fun (car form)))
(cond
((eq fun 'defun)
(let
((tmp (assq (nth 1 form) comp-macro-env)))
(when tmp
(rplaca tmp nil)
(rplacd tmp nil)))
(cons 'defun
(cons (nth 1 form)
(cdr (comp-compile-lambda (cons 'lambda (nthcdr 2 form)))))))
((eq fun 'defmacro)
(let
((code (comp-compile-lambda (cons 'lambda (nthcdr 2 form))))
(tmp (assq (nth 1 form) comp-macro-env)))
(if tmp
(rplacd tmp code)
(setq comp-macro-env (cons (cons (nth 1 form) code) comp-macro-env)))
(cons 'defmacro (cons (nth 1 form) (cdr code)))))
((or (eq fun 'defconst) (eq fun 'defvar))
(let
((doc (nth 3 form)))
(when (and comp-write-docs-p (stringp doc))
(rplaca (nthcdr 3 fo