;;; -*- Mode:LISP; Package:COMPILER; Base:8; Readtable:ZL -*-

;;;    ** (c) Copyright 1980 Massachusetts Institute of Technology **
;;;    ** (c) Copyright 1984 Lisp Machine Inc **
;;;    ** (c) Copyright 1987, GigaMOS Systems Inc. **

;k assembly code is sketched in ORSON:FLEABIT.GENERATE;ASSEM

;transplanted micro-compiler...

(DECLARE (SPECIAL CC-MODE QCMP-OUTPUT))

(defvar *cc-instructions* nil)			;in reversed order
(defvar *entry-points* nil)			;in form suitable for NC:ASSEMBLE-INSTRUCTION-LIST.
						; a list (<number args> . <entry-tag>).

(defvar *inst-number* nil)			;# times to CC-OUT.  For debugging
(defvar *inst-stop-number* nil)			;If non-NIL, bkpt on NTH call to CC-OUT


(defun cross-compile (fctn cc-mode)
 ;this function essentially does no work.  (finding the entry points hardly qualifies..)
  (let ((fun-name nil)				;The name of the function
	(fun-type nil)				;FUNCTION or MACRO
	(word-pointer fctn)			;Scan pointer through function
	(*inst-number* 0)			;Counter
	(*cc-instructions* nil)			;Instructions output
	(*entry-points* nil)			;Entry-points found.
	)
    (multiple-value-setq (fun-name fun-type word-pointer) (cc-1 word-pointer))
    (multiple-value-setq (word-pointer) (cc-2 word-pointer))
    (pop word-pointer)				;flush random ENDLIST
    (multiple-value-setq (nil word-pointer)
      (cc-process-code nil fun-name word-pointer))	;Process code
    (cc-out nil)				;Force-output
    (cc-out nil)
    (values fun-name *cc-instructions* *entry-points*)))

(defun cc-process-code (end-tag fun-name word-pointer)	;Process body of code, but stop if reach end-tag
  (loop for wd = (pop word-pointer)
	while word-pointer
	do (cc-3 wd fun-name)
	(when (and end-tag (eq end-tag wd))
	  (pop word-pointer)
	  (return (values t word-pointer)))))

(defun unknown-word (phase wd)
  (declare (eh:error-reporter))
  (error "Unknown word in ~A: ~S" phase wd))

(defun cc-1 (word-pointer)
  (loop with name
	with type = 'function
	for wd = (first word-pointer)
	do (unless word-pointer
	     (error "Truncated input before QUOTE-BASE"))
	(when (atom wd)
	  (unknown-word "CC-1" wd))
	(case (car wd)
	  ((qtag)
	   (case (second wd)
	     ((quote-base) (return (values name type word-pointer)))))
	  ((param)
	   (set (car wd) (cadr wd)))
	  ((comment endlist s-v-block a-d-l quote self-flavor))
	  ((mfef)
	   (setq name (second wd)))
	  ((macro-function)
	   (setq type 'macro))
	  ((construct-macro)
	   (setq type 'macro))
	  (otherwise (unknown-word "CC-1" wd)))
	(pop word-pointer)))

(defun cc-2 (word-pointer)			;Process QUOTE-LIST 
  (loop for wd = (pop word-pointer)
	do (when (atom wd)
	     (error "Unknown word in CC-2: ~S" wd))
	(case (car wd)
	  ((endlist) (return word-pointer)))))

(defun cc-3 (wd fun-name)			;Translate code
  (cond ((null wd))
	((atom wd)
	 (cc-out wd))
	((and (symbolp (first wd))
	      (or (memq (first wd) '(k:open))	;packages win again!
		  (string-equal (si:package-primary-name (symbol-package (first wd)))
				"K")))
	 (cc-out wd))
	(t (ecase (first wd)
	     ((entry)
	      (let ((tag (gensymbol fun-name "-entry-" (write-to-string (second wd) :base 10.))))
		(push `(,(cadr wd) . ,tag) *entry-points*)
		(cc-out tag)))
	     ((debug-info no-drop-through variables-used-in-lexical-closures breakoffs comment))
	     ((param)
	      (set (first wd) (second wd)))
	     ((restart-tag) (fsignal "RESTART-TAG"))))))

;;see also K-DEST-FROM-LAP-ADDRESS in CROSS-P2.
;;use move or movei
;(defun k-compute-move (dest adr)
;  (cond ((eq (car adr) 'arg)
;	 (cc-out `(k:move ,dest ,(a-n (cadr adr)) k:boxed-right)))
;	((member adr '( (quote nil) (quote t) ))
;	 (cc-out
;	   `(k:move ,dest ,(make-register-list (cdr (assq (cadr adr)
;							  '( (nil . gr:*nil*)
;							    (t   . gr:*t*)))))
;		    k:boxed-right)))
;	((eq (car adr) 'quote)
;	 (cc-out `(k:movei ,dest ,adr k:boxed)))
;	((eq (car adr) 'special)
;	 (cc-out `(k:movei k:o0 (quote ,(cadr adr)) k:boxed k:ch-open))
;	 (cc-out `(k:call (symbol:%symbol-value 1) ,dest)))
;	((eq (car adr) 'quote-vector)
;	 (k-compute-move dest (cadr adr)))
;	(t (ferror nil "Cant compute move ~s ~s" dest adr))))

;(defun make-register-list (k-register-name)
;  (let ((prop (get k-register-name :register)))
;    `(k:register ,k-register-name ., (cdr prop))))



(defun cc-out (X) 
  (when (eq (incf *inst-number*) *inst-stop-number*)
    (break 'inst-stop))
  (cc-final-out x *inst-number*))

;Debugging function
(DEFUN TC (&OPTIONAL (MODE 'PRINT))
  (COND ((EQ MODE 'INPUT)
	 (DOLIST (I (G-L-P QCMP-OUTPUT))
	   (PRINT I)))
	(T
	 (CROSS-COMPILE (G-L-P QCMP-OUTPUT) MODE))))

(defun cc-final-out (x inst-number)
  (ecase cc-mode
    ((print)
     (format t "~%~O:~S" inst-number x))
    ((store)
     (push x *cc-instructions*))))






