home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-06 | 35.0 KB | 1,068 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.
-
-
- ;;; Notes:
- ;;;
- ;;; Instruction Encoding
- ;;; ====================
- ;;; Instructions which get an argument (with opcodes of zero up to
- ;;; `op-last-with-args') encode the type of argument in the low 3 bits
- ;;; of their opcode (this is why these instructions take up 8 opcodes).
- ;;; A value of 0 to 5 (inclusive) is the literal argument, value of
- ;;; 6 means the next byte holds the argument, or a value of 7 says
- ;;; that the next two bytes are used to encode the argument (in big-
- ;;; endian form, i.e. first extra byte has the high 8 bits)
- ;;;
- ;;; All instructions greater than the `op-last-before-jmps' are branches,
- ;;; currently only absolute destinations are supported, all branch
- ;;; instructions encode their destination in the following two bytes (also
- ;;; in big-endian form).
- ;;;
- ;;; Any opcode between `op-last-with-args' and `op-last-before-jmps' is
- ;;; a straightforward single-byte instruction.
- ;;;
- ;;; The machine simulated by lispmach.c is a simple stack-machine, each
- ;;; call to the byte-code interpreter gets its own stack; the size of
- ;;; stack needed is calculated by the compiler.
- ;;;
- ;;; If you hadn't already noticed I based this on the Emacs version 18
- ;;; byte-compiler.
- ;;;
- ;;; Constants
- ;;; =========
- ;;; `defconst' forms have to be used with some care. The compiler assumes
- ;;; that the value of the constant is always the same, whenever it is
- ;;; evaluated. It may even be evaluated more than once.
- ;;;
- ;;; In general, any symbols declared as constants (by defconst) have their
- ;;; values set in stone. These values are hard-coded into the compiled
- ;;; byte-code.
- ;;;
- ;;; Also, the value of a constant-symbol is *not* likely to be eq to itself!
- ;;;
- ;;; Use constants as you would use macros in C, i.e. to define values which
- ;;; have to be the same throughout a module. For example, this compiler uses
- ;;; defconst forms to declare the instruction opcodes.
- ;;;
- ;;; If you have doubts about whether or not to use constants -- don't; it may
- ;;; lead to subtle bugs.
-
-
- (provide 'compiler)
-
-
- ;; Options
- (defvar comp-write-docs 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-lognot 0x5c)
- (defconst op-not 0x5d)
- (defconst op-logior-2 0x5e)
- (defconst op-logand-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-return 0x7e)
- (defconst op-reverse 0x7f) ;new 12/7/94
- (defconst op-nreverse 0x80)
- (defconst op-assoc 0x81)
- (defconst op-assq 0x82)
- (defconst op-rassoc 0x83)
- (defconst op-rassq 0x84)
- (defconst op-last 0x85)
- (defconst op-mapcar 0x86)
- (defconst op-mapc 0x87)
- (defconst op-member 0x88)
- (defconst op-memq 0x89)
- (defconst op-delete 0x8a)
- (defconst op-delq 0x8b)
- (defconst op-delete-if 0x8c)
- (defconst op-delete-if-not 0x8d)
- (defconst op-copy-sequence 0x8e)
- (defconst op-sequencep 0x8f)
- (defconst op-functionp 0x90)
- (defconst op-special-form-p 0x91)
- (defconst op-subrp 0x92)
- (defconst op-eql 0x93)
- (defconst op-logxor-2 0x94) ;new 23-8-94
-
- (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-markp 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-jn 0xfc) ;pop the stack, if nil, jmp x
- (defconst op-jt 0xfd) ;pop the stack, if t, jmp x
- (defconst op-jnp 0xfe) ;if stk[0] nil, jmp x, else pop
- (defconst op-jtp 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 0xff) ;max arg held in 2-byte instruction
- (defconst comp-max-3-byte-arg 0xffff) ;max arg help in 3-byte instruction
-
-
- ;; Environment of this byte code sequence being compiled
-
- (defvar comp-constant-alist '()) ;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 '()) ;alist of (NAME . MACRO-DEF)
- (defvar comp-const-env '()) ;alist of (NAME . CONST-DEF)
-
-
- (defvar comp-top-level-compiled
- '(if cond when unless let let* catch unwind-protect error-protect
- with-buffer with-window progn prog1 prog2 while and or)
- "List of symbols, when the name of the function called by a top-level form
- is one of these that form is compiled.")
-
- ;;;###autoload
- (defun 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')."
- (interactive "fLisp file to compile:")
- (let
- (src-file dst-file form
- comp-macro-env
- comp-const-env)
- (when (and (setq src-file (open file-name "r"))
- (setq dst-file (open (concat file-name ?c) "w")))
- (format dst-file
- ";;; Source file: %s\n;;; Compiled by %s@%s on %s\n;;; Jade %d.%d\n"
- file-name (user-login-name) (system-name) (current-time-string)
- (major-version-number) (minor-version-number))
- (error-protect
- (unwind-protect
- (let
- (form)
- (message (concat "Compiling " file-name "...") t)
- (while (not (file-eof-p src-file))
- (when (setq form (read src-file))
- (cond
- ((memq (car form) '(defun defmacro defvar defconst require))
- (setq form (comp-compile-top-form form)))
- ((memq (car form) comp-top-level-compiled)
- ;; Compile this form
- (setq form (compile-form form))))
- (when form
- (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)))
- ;; Hack to signal error without entering the debugger (again)
- (throw 'error error-info)))
- t)))
-
- ;;;###autoload
- (defun compile-directory (dir-name &optional force-p exclude-list)
- "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.
- EXCLUDE-LIST is a list of files which shouldn't be compiled."
- (interactive "DDirectory of Lisp files to compile:\nP")
- (let
- ((dir (directory-files dir-name)))
- (while (consp dir)
- (when (and (regexp-match "\\.jl$" (car dir))
- (null (member (car dir) exclude-list)))
- (let*
- ((file (file-name-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))
-
- (defvar compile-lib-exclude-list
- '("autoload.jl"))
-
- ;;;###autoload
- (defun compile-lisp-lib (&optional 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 and
- that files which shouldn't be compiled aren't."
- (interactive "P")
- (let
- ((comp-write-docs t))
- (compile-directory lisp-lib-dir force-p compile-lib-exclude-list)))
-
-
- (put 'compile-error 'error-message "Compilation mishap")
- (defun comp-error (&rest data)
- (signal 'compile-error data))
-
- ;; Compile a form which occurred at the `top-level' into a byte code form.
- ;; defuns, defmacros, defvars, etc... are treated specially.
- ;; require forms are evaluated before being output uncompiled; this is so
- ;; any macros are brought in before they're used.
- (defun comp-compile-top-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)))))
- ((eq fun 'defconst)
- (let
- ((value (eval (nth 2 form)))
- (doc (nth 3 form)))
- (when (and comp-write-docs (stringp doc))
- (rplaca (nthcdr 3 form) (add-doc-string doc)))
- (setq comp-const-env (cons (cons (nth 1 form) value) comp-const-env)))
- form)
- ((eq fun 'defvar)
- (let
- ((doc (nth 3 form)))
- (when (and comp-write-docs (stringp doc))
- (rplaca (nthcdr 3 form) (add-doc-string doc))))
- form)
- ((eq fun 'require)
- (eval form)
- form)
- (t
- (comp-error "Shouldn't have got here!")))))
-
- ;;;###autoload
- (defun compile-form (form)
- "Compile the Lisp form FORM into a byte code form."
- (let
- (comp-constant-alist
- (comp-constant-index 0)
- (comp-current-stack 0)
- (comp-max-stack 0)
- comp-output
- (comp-output-pc 0))
- (comp-compile-form form)
- (when comp-output
- (list 'jade-byte-code (comp-make-code-string) (comp-make-const-vec)
- comp-max-stack))))
-
- ;; Turn the alist of byte codes into a string
- (defun comp-make-code-string ()
- (let
- ((code-string (make-string comp-output-pc ?*))
- (data comp-output))
- (while (consp data)
- (aset code-string (cdr (car data)) (car (car data)))
- (setq data (cdr data)))
- code-string))
-
- ;; Turn the alist of constants into a vector
- (defun comp-make-const-vec ()
- (let
- ((vec (make-vector comp-constant-index))
- (consts comp-constant-alist))
- (while (consp consts)
- (aset vec (cdr (car consts)) (car (car consts)))
- (setq consts (cdr consts)))
- vec))
-
- ;; Increment the current stack size, setting the maximum stack size if
- ;; necessary
- (defun comp-inc-stack ()
- (when (> (setq comp-current-stack (1+ comp-current-stack)) comp-max-stack)
- (setq comp-max-stack comp-current-stack)))
-
- ;; Decrement the current stack usage
- (defmacro comp-dec-stack (&optional n)
- (list 'setq 'comp-current-stack
- (if n
- (list '- 'comp-current-stack n)
- (list '1- 'comp-current-stack))))
-
- ;; Compile one form so that its value ends up on the stack when interpreted
- (defun comp-compile-form (form)
- (cond
- ((eq form nil)
- (comp-write-op op-nil)
- (comp-inc-stack))
- ((eq form t)
- (comp-write-op op-t)
- (comp-inc-stack))
- ((symbolp form)
- (let
- (val)
- (cond
- ((const-variable-p form)
- ;; A constant already interned
- (comp-write-op op-push (comp-add-constant (symbol-value form)))
- (comp-inc-stack))
- ((setq val (assq form comp-const-env))
- ;; A constant from this file
- (comp-compile-form (cdr val)))
- (t
- ;; Not a constant
- (comp-write-op op-vrefc (comp-add-constant form))
- (comp-inc-stack)))))
- ((consp form)
- (let
- (fun)
- (if (and (symbolp (car form)) (setq fun (get (car form) 'compile-fun)))
- (funcall fun form)
- (setq form (macroexpand form comp-macro-env))
- (if (and (symbolp (car form))
- (setq fun (get (car form) 'compile-fun)))
- (funcall fun form)
- (setq fun (car form))
- (cond
- ((symbolp fun)
- (comp-compile-constant fun))
- ((and (consp fun) (eq (car fun) 'lambda))
- (comp-compile-constant (comp-compile-lambda fun)))
- (t
- (comp-error "Bad function name" fun)))
- (setq form (cdr form))
- (let
- ((i 0))
- (while (consp form)
- (comp-compile-form (car form))
- (setq i (1+ i)
- form (cdr form)))
- (comp-write-op op-call i)
- (comp-dec-stack i))))))
- (t
- (comp-compile-constant form))))
-
- ;; Push a constant onto the stack
- (defun comp-compile-constant (form)
- (comp-write-op op-push (comp-add-constant form))
- (comp-inc-stack))
-
- ;; Put a constant into the alist of constants, returning its index number.
- ;; It won't be added twice if it's already there.
- (defun comp-add-constant (const)
- (unless (cdr (assoc const comp-constant-alist))
- (setq comp-constant-alist (cons (cons const comp-constant-index)
- comp-constant-alist)
- comp-constant-index (1+ comp-constant-index))
- (1- comp-constant-index)))
-
- ;; Compile a list of forms, the last form's evaluated value is left on
- ;; the stack. If the list is empty nil is pushed.
- (defun comp-compile-body (body)
- (if (null body)
- (progn
- (comp-write-op op-nil)
- (comp-inc-stack))
- (while (consp body)
- (comp-compile-form (car body))
- (when (cdr body)
- (comp-write-op op-pop)
- (comp-dec-stack))
- (setq body (cdr body)))))
-
- ;; From LIST, `(lambda (ARGS) [DOC-STRING] BODY ...)' returns a new list of,
- ;; `(lambda (ARGS) [DOC-STRING] (jade-byte-code ...))'
- (defun comp-compile-lambda (list)
- (let
- ((body (nthcdr 2 list))
- new-head)
- (cond
- ((stringp (car body))
- (setq body (cdr body)
- new-head (list 'lambda (nth 1 list)
- (if comp-write-docs
- (add-doc-string (nth 2 list))
- (nth 2 list)))))
- (t
- (setq new-head (list 'lambda (nth 1 list)))))
- ;; Check for an `(interactive ...)' declaration; it doesn't get compiled
- (when (eq (car (car body)) 'interactive)
- (setq new-head (nconc new-head (list (car body)))
- body (cdr body)))
- (nconc new-head (cons (compile-form (cons 'progn body)) nil))))
-
-
- ;; Managing the output code
-
- ;; Return a new label
- (defmacro comp-make-label ()
- ;; a label is, (PC-OF-LABEL . (LIST-OF-REFERENCES))
- '(cons nil nil))
-
- ;; Output a branch instruction to the label LABEL, if LABEL has not been
- ;; located yet this branch is recorded for later backpatching.
- (defun comp-compile-jmp (opcode label)
- (comp-byte-out opcode)
- (cond
- ((numberp (car label))
- ;; we know the final offset of this label so use it
- (comp-byte-out (lsh (car label) -8))
- (comp-byte-out (logand (car label) 0xff)))
- (t
- ;; offset unknown, show we need it patched in later
- (rplacd label (cons comp-output-pc (cdr label)))
- (setq comp-output-pc (+ comp-output-pc 2)))))
-
- ;; Set the address of the label LABEL, any references to it are patched
- ;; with its address.
- (defun comp-set-label (label)
- (when (> comp-output-pc comp-max-3-byte-arg)
- (comp-error "Jump destination overflow!"))
- (rplaca label comp-output-pc)
- (setq label (cdr label))
- (while (consp label)
- (setq comp-output (cons (cons (lsh comp-output-pc -8) (car label))
- (cons (cons (logand comp-output-pc 0xff)
- (1+ (car label)))
- comp-output))
- label (cdr label))))
-
- ;; Output one opcode and its optional argument
- (defun comp-write-op (opcode &optional arg)
- (cond
- ((null arg)
- (comp-byte-out opcode))
- ((<= arg comp-max-1-byte-arg)
- (comp-byte-out (+ opcode arg)))
- ((<= arg comp-max-2-byte-arg)
- ;; 2-byte instruction
- (comp-byte-out (+ opcode 6))
- (comp-byte-out arg))
- ((<= arg comp-max-3-byte-arg)
- ;; 3-byte instruction
- (comp-byte-out (+ opcode 7))
- (comp-byte-out (lsh arg -8))
- (comp-byte-out (logand arg 0xff)))
- (t
- (comp-error "Opcode overflow!"))))
-
- ;; Output one byte
- (defun comp-byte-out (byte)
- (setq comp-output (cons (cons byte comp-output-pc) comp-output)
- comp-output-pc (1+ comp-output-pc)))
-
-
- ;; Functions which compile non-standard functions (ie special-forms)
-
- (put 'if 'compile-fun 'comp-compile-if)
- (defun comp-compile-if (form)
- (comp-compile-form (nth 1 form))
- (if (= (length form) 3)
- (let*
- ((end-label (comp-make-label)))
- (comp-compile-jmp op-jnp end-label)
- (comp-dec-stack)
- (comp-compile-form (nth 2 form))
- (comp-set-label end-label))
- (let*
- ((end-label (comp-make-label))
- (else-label (comp-make-label)))
- (comp-compile-jmp op-jn else-label)
- (comp-dec-stack)
- (comp-compile-form (nth 2 form))
- (comp-compile-jmp op-jmp end-label)
- (comp-set-label else-label)
- (comp-dec-stack)
- (comp-compile-body (nthcdr 3 form))
- (comp-set-label end-label))))
-
- (put 'when 'compile-fun 'comp-compile-when)
- (defun comp-compile-when (form)
- (comp-compile-form (nth 1 form))
- (let
- ((end-label (comp-make-label)))
- (comp-compile-jmp op-jnp end-label)
- (comp-dec-stack)
- (comp-compile-body (nthcdr 2 form))
- (comp-set-label end-label)))
-
- (put 'unless 'compile-fun 'comp-compile-unless)
- (defun comp-compile-unless (form)
- (comp-compile-form (nth 1 form))
- (let
- ((end-label (comp-make-label)))
- (comp-compile-jmp op-jtp end-label)
- (comp-dec-stack)
- (comp-compile-body (nthcdr 2 form))
- (comp-set-label end-label)))
-
- (put 'quote 'compile-fun 'comp-compile-quote)
- (defun comp-compile-quote (form)
- (comp-compile-constant (car (cdr form))))
-
- (put 'function 'compile-fun 'comp-compile-function)
- (defun comp-compile-function (form)
- (setq form (car (cdr form)))
- (if (symbolp form)
- (comp-compile-constant form)
- (comp-compile-constant (comp-compile-lambda form))))
-
- (put 'while 'compile-fun 'comp-compile-while)
- (defun comp-compile-while (form)
- (let*
- ((tst-label (comp-make-label))
- (end-label (comp-make-label)))
- (comp-set-label tst-label)
- (comp-compile-form (nth 1 form))
- (comp-compile-jmp op-jnp end-label)
- (comp-dec-stack)
- (comp-compile-body (nthcdr 2 form))
- (comp-write-op op-pop)
- (comp-dec-stack)
- (comp-compile-jmp op-jmp tst-label)
- (comp-set-label end-label)
- (comp-inc-stack)))
-
- (put 'progn 'compile-fun 'comp-compile-progn)
- (defun comp-compile-progn (form)
- (comp-compile-body (cdr form)))
-
- (put 'prog1 'compile-fun 'comp-compile-prog1)
- (defun comp-compile-prog1 (form)
- (comp-compile-form (nth 1 form))
- (comp-compile-body (nthcdr 2 form))
- (comp-write-op op-pop)
- (comp-dec-stack))
-
- (put 'prog2 'compile-fun 'comp-compile-prog2)
- (defun comp-compile-prog2 (form)
- (comp-compile-form (nth 1 form))
- (comp-write-op op-pop)
- (comp-dec-stack)
- (comp-compile-form (nth 2 form))
- (comp-compile-body (nthcdr 3 form))
- (comp-write-op op-pop)
- (comp-dec-stack))
-
- (put 'setq 'compile-fun 'comp-compile-setq)
- (defun comp-compile-setq (form)
- (setq form (cdr form))
- (while (and (consp form) (consp (cdr form)))
- (comp-compile-form (car (cdr form)))
- (unless (consp (nthcdr 2 form))
- (comp-write-op op-dup)
- (comp-inc-stack))
- (comp-write-op op-vsetc (comp-add-constant (car form)))
- (comp-dec-stack)
- (setq form (nthcdr 2 form))))
-
- (put 'set 'compile-fun 'comp-compile-set)
- (defun comp-compile-set (form)
- (comp-compile-form (nth 2 form))
- (comp-write-op op-dup)
- (comp-inc-stack)
- (comp-compile-form (nth 1 form))
- (comp-write-op op-vset)
- (comp-dec-stack 2))
-
- (put 'fset 'compile-fun 'comp-compile-fset)
- (defun comp-compile-fset (form)
- (comp-compile-form (nth 2 form))
- (comp-write-op op-dup)
- (comp-inc-stack)
- (comp-compile-form (nth 1 form))
- (comp-write-op op-fset)
- (comp-dec-stack 2))
-
- (put 'let* 'compile-fun 'comp-compile-let*)
- (defun comp-compile-let* (form)
- (let
- ((list (car (cdr form))))
- (comp-write-op op-init-bind)
- (while (consp list)
- (cond
- ((consp (car list))
- (let
- ((tmp (car list)))
- (comp-compile-body (cdr tmp))
- (comp-write-op op-bind (comp-add-constant (car tmp)))))
- (t
- (comp-write-op op-nil)
- (comp-inc-stack)
- (comp-write-op op-bind (comp-add-constant (car list)))))
- (comp-dec-stack)
- (setq list (cdr list)))
- (comp-compile-body (nthcdr 2 form))
- (comp-write-op op-unbind)))
-
- (put 'let 'compile-fun 'comp-compile-let)
- (defun comp-compile-let (form)
- (let
- ((list (car (cdr form)))
- (sym-stk nil))
- (comp-write-op op-init-bind)
- (while (consp list)
- (cond
- ((consp (car list))
- (setq sym-stk (cons (car (car list)) sym-stk))
- (comp-compile-body (cdr (car list))))
- (t
- (setq sym-stk (cons (car list) sym-stk))
- (comp-write-op op-nil)
- (comp-inc-stack)))
- (setq list (cdr list)))
- (while (consp sym-stk)
- (comp-write-op op-bind (comp-add-constant (car sym-stk)))
- (comp-dec-stack)
- (setq sym-stk (cdr sym-stk)))
- (comp-compile-body (nthcdr 2 form))
- (comp-write-op op-unbind)))
-
- (put 'defun 'compile-fun 'comp-compile-defun)
- (defun comp-compile-defun (form)
- (comp-compile-constant (nth 1 form))
- (comp-write-op op-dup)
- (comp-inc-stack)
- (comp-compile-constant (comp-compile-lambda (cons 'lambda (nthcdr 2 form))))
- (comp-write-op op-swap)
- (comp-write-op op-fset)
- (comp-dec-stack 2))
-
- (put 'defmacro 'compile-fun 'comp-compile-defmacro)
- (defun comp-compile-defmacro (form)
- (comp-compile-constant (nth 1 form))
- (comp-write-op op-dup)
- (comp-inc-stack)
- (comp-compile-constant (cons 'macro (comp-compile-lambda (cons 'lambda (nthcdr 2 form)))))
- (comp-write-op op-swap)
- (comp-write-op op-fset)
- (comp-dec-stack 2))
-
- (put 'cond 'compile-fun 'comp-compile-cond)
- (defun comp-compile-cond (form)
- (let
- ((end-label (comp-make-label)))
- (setq form (cdr form))
- (while (consp form)
- (let
- ((subl (car form))
- (next-label (comp-make-label)))
- (comp-compile-form (car subl))
- (comp-dec-stack)
- (cond
- ((consp (cdr subl))
- (comp-compile-jmp op-jn next-label)
- (comp-compile-body (cdr subl))
- (comp-dec-stack)
- (comp-compile-jmp op-jmp end-label)
- (comp-set-label next-label))
- (t
- (comp-compile-jmp op-jtp end-label)))
- (setq form (cdr form))))
- (comp-write-op op-nil)
- (comp-inc-stack)
- (comp-set-label end-label)))
-
- (put 'or 'compile-fun 'comp-compile-or)
- (defun comp-compile-or (form)
- (let
- ((end-label (comp-make-label)))
- (setq form (cdr form))
- (while (consp form)
- (comp-compile-form (car form))
- (comp-dec-stack)
- (when (cdr form)
- (comp-compile-jmp op-jtp end-label))
- (setq form (cdr form)))
- (comp-inc-stack)
- (comp-set-label end-label)))
-
- (put 'and 'compile-fun 'comp-compile-and)
- (defun comp-compile-and (form)
- (let
- ((end-label (comp-make-label)))
- (setq form (cdr form))
- (while (consp form)
- (comp-compile-form (car form))
- (comp-dec-stack)
- (when (cdr form)
- (comp-compile-jmp op-jnp end-label))
- (setq form (cdr form)))
- (comp-inc-stack)
- (comp-set-label end-label)))
-
- (put 'catch 'compile-fun 'comp-compile-catch)
- (defun comp-compile-catch (form)
- (comp-compile-constant (compile-form (cons 'progn (nthcdr 2 form))))
- (comp-compile-constant (nth 1 form))
- (comp-write-op op-catch-kludge)
- (comp-dec-stack))
-
- (put 'unwind-protect 'compile-fun 'comp-compile-unwind-pro)
- (defun comp-compile-unwind-pro (form)
- (comp-compile-constant (compile-form (cons 'progn (nthcdr 2 form))))
- (comp-write-op op-unwind-pro)
- (comp-dec-stack)
- (comp-compile-form (nth 1 form))
- (comp-write-op op-un-unwind-pro))
-
- (put 'error-protect 'compile-fun 'comp-compile-error-protect)
- (defun comp-compile-error-protect (form)
- (let
- ((i 0))
- (setq form (cdr form))
- (unless (consp form)
- (comp-error "No FORM to `error-protect'" form))
- (comp-compile-constant (compile-form (car form)))
- (setq form (cdr form))
- (while (consp form)
- (let
- ((handler (car form)))
- (unless (consp handler)
- (comp-error "Badly formed handler to `error-protect'" form))
- (comp-compile-constant (list (car handler)
- (compile-form (cons 'progn
- (cdr handler)))))
- (setq form (cdr form)
- i (1+ i))))
- (comp-compile-constant (1+ i))
- (comp-write-op op-error-pro)
- (comp-dec-stack i)))
-
- (put 'list 'compile-fun 'comp-compile-list)
- (defun comp-compile-list (form)
- (let
- ((count 0))
- (setq form (cdr form))
- (while (consp form)
- (comp-compile-form (car form))
- (setq
- count (1+ count)
- form (cdr form)))
- (comp-write-op op-list count)
- (comp-dec-stack (1- count))))
-
- (put 'with-buffer 'compile-fun 'comp-compile-with-buffer)
- (defun comp-compile-with-buffer (form)
- (comp-compile-form (nth 1 form))
- (comp-write-op op-swap-buffer)
- (comp-compile-body (nthcdr 2 form))
- (comp-write-op op-swap)
- (comp-write-op op-swap-buffer)
- (comp-write-op op-pop)
- (comp-dec-stack))
-
- (put 'with-window 'compile-fun 'comp-compile-with-window)
- (defun comp-compile-with-window (form)
- (comp-compile-form (nth 1 form))
- (comp-write-op op-swap-window)
- (comp-compile-body (nthcdr 2 form))
- (comp-write-op op-swap)
- (comp-write-op op-swap-window)
- (comp-write-op op-pop)
- (comp-dec-stack))
-
- (put '- 'compile-fun 'comp-compile-minus)
- (put '- 'compile-opcode op-minus-2)
- (defun comp-compile-minus (form)
- (if (/= (length form) 2)
- (comp-compile-binary-op form)
- (comp-compile-form (car (cdr form)))
- (comp-write-op op-negate)))
-
- ;; Instruction with no arguments
- (defun comp-compile-0-args (form)
- (comp-write-op (get (car form) 'compile-opcode) 0)
- (comp-inc-stack))
-
- ;; Instruction taking 1 arg on the stack
- (defun comp-compile-1-args (form)
- (comp-compile-form (nth 1 form))
- (comp-write-op (get (car form) 'compile-opcode) 0))
-
- ;; Instruction taking 2 args on the stack
- (defun comp-compile-2-args (form)
- (comp-compile-form (nth 1 form))
- (comp-compile-form (nth 2 form))
- (comp-write-op (get (car form) 'compile-opcode) 0)
- (comp-dec-stack))
-
- ;; Instruction taking 3 args on the stack
- (defun comp-compile-3-args (form)
- (comp-compile-form (nth 1 form))
- (comp-compile-form (nth 2 form))
- (comp-compile-form (nth 3 form))
- (comp-write-op (get (car form) 'compile-opcode) 0)
- (comp-dec-stack 2))
-
- ;; Compile a form `(OP ARG1 ARG2 ARG3 ...)' into as many two argument
- ;; instructions as needed (PUSH ARG1; PUSH ARG2; OP; PUSH ARG3; OP; ...)
- (defun comp-compile-binary-op (form)
- (let
- ((opcode (get (car form) 'compile-opcode)))
- (setq form (cdr form))
- (unless (>= (length form) 2)
- (comp-error "Too few args to binary operator" form))
- (comp-compile-form (car form))
- (setq form (cdr form))
- (while (consp form)
- (comp-compile-form (car form))
- (comp-write-op opcode)
- (comp-dec-stack)
- (setq form (cdr form)))))
-
-
- ;; Opcode properties for the generic instructions, in a progn for compiled
- ;; speed
-
- (progn
- (put 'cons 'compile-fun 'comp-compile-2-args)
- (put 'cons 'compile-opcode op-cons)
- (put 'car 'compile-fun 'comp-compile-1-args)
- (put 'car 'compile-opcode op-car)
- (put 'cdr 'compile-fun 'comp-compile-1-args)
- (put 'cdr 'compile-opcode op-cdr)
- (put 'rplaca 'compile-fun 'comp-compile-2-args)
- (put 'rplaca 'compile-opcode op-rplaca)
- (put 'rplacd 'compile-fun 'comp-compile-2-args)
- (put 'rplacd 'compile-opcode op-rplacd)
- (put 'nth 'compile-fun 'comp-compile-2-args)
- (put 'nth 'compile-opcode op-nth)
- (put 'nthcdr 'compile-fun 'comp-compile-2-args)
- (put 'nthcdr 'compile-opcode op-nthcdr)
- (put 'aset 'compile-fun 'comp-compile-3-args)
- (put 'aset 'compile-opcode op-aset)
- (put 'aref 'compile-fun 'comp-compile-2-args)
- (put 'aref 'compile-opcode op-aref)
- (put 'length 'compile-fun 'comp-compile-1-args)
- (put 'length 'compile-opcode op-length)
- (put 'eval 'compile-fun 'comp-compile-1-args)
- (put 'eval 'compile-opcode op-eval)
- (put '+ 'compile-fun 'comp-compile-binary-op)
- (put '+ 'compile-opcode op-plus-2)
- (put '* 'compile-fun 'comp-compile-binary-op)
- (put '* 'compile-opcode op-product-2)
- (put '/ 'compile-fun 'comp-compile-binary-op)
- (put '/ 'compile-opcode op-divide-2)
- (put '% 'compile-fun 'comp-compile-binary-op)
- (put '% 'compile-opcode op-mod-2)
- (put 'lognot 'compile-fun 'comp-compile-1-args)
- (put 'lognot 'compile-opcode op-lognot)
- (put 'not 'compile-fun 'comp-compile-1-args)
- (put 'not 'compile-opcode op-not)
- (put 'logior 'compile-fun 'comp-compile-binary-op)
- (put 'logior 'compile-opcode op-logior-2)
- (put 'logxor 'compile-fun 'comp-compile-binary-op)
- (put 'logxor 'compile-opcode op-logxor-2)
- (put 'logand 'compile-fun 'comp-compile-binary-op)
- (put 'logand 'compile-opcode op-logand-2)
- (put 'equal 'compile-fun 'comp-compile-2-args)
- (put 'equal 'compile-opcode op-equal)
- (put 'eq 'compile-fun 'comp-compile-2-args)
- (put 'eq 'compile-opcode op-eq)
- (put '= 'compile-fun 'comp-compile-2-args)
- (put '= 'compile-opcode op-num-eq)
- (put '/= 'compile-fun 'comp-compile-2-args)
- (put '/= 'compile-opcode op-num-noteq)
- (put '> 'compile-fun 'comp-compile-2-args)
- (put '> 'compile-opcode op-gtthan)
- (put '< 'compile-fun 'comp-compile-2-args)
- (put '< 'compile-opcode op-ltthan)
- (put '>= 'compile-fun 'comp-compile-2-args)
- (put '>= 'compile-opcode op-gethan)
- (put '<= 'compile-fun 'comp-compile-2-args)
- (put '<= 'compile-opcode op-lethan)
- (put '1+ 'compile-fun 'comp-compile-1-args)
- (put '1+ 'compile-opcode op-inc)
- (put '1- 'compile-fun 'comp-compile-1-args)
- (put '1- 'compile-opcode op-dec)
- (put 'lsh 'compile-fun 'comp-compile-2-args)
- (put 'lsh 'compile-opcode op-lsh)
- (put 'zerop 'compile-fun 'comp-compile-1-args)
- (put 'zerop 'compile-opcode op-zerop)
- (put 'null 'compile-fun 'comp-compile-1-args)
- (put 'null 'compile-opcode op-null)
- (put 'atom 'compile-fun 'comp-compile-1-args)
- (put 'atom 'compile-opcode op-atom)
- (put 'consp 'compile-fun 'comp-compile-1-args)
- (put 'consp 'compile-opcode op-consp)
- (put 'listp 'compile-fun 'comp-compile-1-args)
- (put 'listp 'compile-opcode op-listp)
- (put 'numberp 'compile-fun 'comp-compile-1-args)
- (put 'numberp 'compile-opcode op-numberp)
- (put 'stringp 'compile-fun 'comp-compile-1-args)
- (put 'stringp 'compile-opcode op-stringp)
- (put 'vectorp 'compile-fun 'comp-compile-1-args)
- (put 'vectorp 'compile-opcode op-vectorp)
- (put 'throw 'compile-fun 'comp-compile-2-args)
- (put 'throw 'compile-opcode op-throw)
- (put 'fboundp 'compile-fun 'comp-compile-1-args)
- (put 'fboundp 'compile-opcode op-fboundp)
- (put 'boundp 'compile-fun 'comp-compile-1-args)
- (put 'boundp 'compile-opcode op-boundp)
- (put 'symbolp 'compile-fun 'comp-compile-1-args)
- (put 'symbolp 'compile-opcode op-symbolp)
- (put 'get 'compile-fun 'comp-compile-2-args)
- (put 'get 'compile-opcode op-get)
- (put 'put 'compile-fun 'comp-compile-3-args)
- (put 'put 'compile-opcode op-put)
- (put 'signal 'compile-fun 'comp-compile-2-args)
- (put 'signal 'compile-opcode op-signal)
- (put 'return 'compile-fun 'comp-compile-1-args)
- (put 'return 'compile-opcode op-return)
- (put 'reverse 'compile-fun 'comp-compile-1-args) ; new 12/7/94
- (put 'reverse 'compile-opcode op-reverse)
- (put 'nreverse 'compile-fun 'comp-compile-1-args)
- (put 'nreverse 'compile-opcode op-nreverse)
- (put 'assoc 'compile-fun 'comp-compile-2-args)
- (put 'assoc 'compile-opcode op-assoc)
- (put 'assq 'compile-fun 'comp-compile-2-args)
- (put 'assq 'compile-opcode op-assq)
- (put 'rassoc 'compile-fun 'comp-compile-2-args)
- (put 'rassoc 'compile-opcode op-rassoc)
- (put 'rassq 'compile-fun 'comp-compile-2-args)
- (put 'rassq 'compile-opcode op-rassq)
- (put 'last 'compile-fun 'comp-compile-2-args)
- (put 'last 'compile-opcode op-last)
- (put 'mapcar 'compile-fun 'comp-compile-2-args)
- (put 'mapcar 'compile-opcode op-mapcar)
- (put 'mapc 'compile-fun 'comp-compile-2-args)
- (put 'mapc 'compile-opcode op-mapc)
- (put 'member 'compile-fun 'comp-compile-2-args)
- (put 'member 'compile-opcode op-member)
- (put 'memq 'compile-fun 'comp-compile-2-args)
- (put 'memq 'compile-opcode op-memq)
- (put 'delete 'compile-fun 'comp-compile-2-args)
- (put 'delete 'compile-opcode op-delete)
- (put 'delq 'compile-fun 'comp-compile-2-args)
- (put 'delq 'compile-opcode op-delq)
- (put 'delete-if 'compile-fun 'comp-compile-2-args)
- (put 'delete-if 'compile-opcode op-delete-if)
- (put 'delete-if-not 'compile-fun 'comp-compile-2-args)
- (put 'delete-if-not 'compile-opcode op-delete-if-not)
- (put 'copy-sequence 'compile-fun 'comp-compile-1-args)
- (put 'copy-sequence 'compile-opcode op-copy-sequence)
- (put 'sequencep 'compile-fun 'comp-compile-1-args)
- (put 'sequencep 'compile-opcode op-sequencep)
- (put 'functionp 'compile-fun 'comp-compile-1-args)
- (put 'functionp 'compile-opcode op-functionp)
- (put 'special-form-p 'compile-fun 'comp-compile-1-args)
- (put 'special-form-p 'compile-opcode op-special-form-p)
- (put 'subrp 'compile-fun 'comp-compile-1-args)
- (put 'subrp 'compile-opcode op-subrp)
- (put 'eql 'compile-fun 'comp-compile-2-args)
- (put 'eql 'compile-opcode op-eql)
-
- (put 'set-current-buffer 'compile-fun 'comp-compile-2-args)
- (put 'set-current-buffer 'compile-opcode op-set-current-buffer)
- (put 'current-buffer 'compile-fun 'comp-compile-1-args)
- (put 'current-buffer 'compile-opcode op-current-buffer)
- (put 'bufferp 'compile-fun 'comp-compile-1-args)
- (put 'bufferp 'compile-opcode op-bufferp)
- (put 'markp 'compile-fun 'comp-compile-1-args)
- (put 'markp 'compile-opcode op-markp)
- (put 'windowp 'compile-fun 'comp-compile-1-args)
- (put 'windowp 'compile-opcode op-windowp))
-