|
|
1.1 root 1: (include-if (null (get 'chead 'version)) "../chead.l")
2: (Liszt-file tlev
3: "$Header: tlev.l,v 1.13 83/09/12 15:25:29 layer Exp $")
4:
5: ;;; ---- t l e v top level interface
6: ;;;
7: ;;; -[Fri Sep 2 21:50:34 1983 by layer]-
8:
9: ;--- lisztinit : called upon compiler startup. If there are any args
10: ; on the command line, we build up a call to liszt, which
11: ; will do the compile. Afterwards we exit.
12: ;
13: (def lisztinit
14: (lambda nil
15: (setq fl-asm nil) ; insure it as correct value in case of int
16: (let ((args (command-line-args)))
17: (if args
18: then (signal 2 'liszt-interrupt-signal) ; die on int
19: (signal 15 'liszt-interrupt-signal) ; die on sigterm
20: (setq user-top-level nil)
21: (exit (apply 'liszt args))
22: else (patom compiler-name)
23: (patom " [")(patom franz-minor-version-number)(patom "]")
24: (terpr poport)
25: (setq user-top-level nil)))))
26:
27: (setq user-top-level 'lisztinit)
28:
29: ;--- liszt - v-x : list containing file name to compile and optionaly
30: ; and output file name for the assembler source.
31: ;
32: (def liszt
33: (nlambda (v-x)
34: (prog (piport v-root v-ifile v-sfile v-ofile
35: vp-ifile vp-sfile vps-crap
36: vps-include vns-include
37: asm-exit-status ntem temgc temcp
38: rootreal g-arrayspecs out-path
39: g-decls g-stdref pre-eval include-files
40: g-fname g-trueop g-falseop g-didvectorcode
41: tem temr starttime startptime startgccount
42: fl-asm fl-warn fl-verb fl-inter fl-xref fl-uci
43: fl-run fl-case fl-anno g-optionalp
44: liszt-process-forms in-line-lambda-number
45: g-skipcode g-dropnpcnt g-complrname)
46:
47: ;in case "S" switch given, set asm-exit-status
48: ; to 0 (so garbage won't be returned).
49: (setq asm-exit-status 0)
50:
51: ; turn on monitoring if it exists
52: #+monitoring
53: (errset (progn (monitor t) ; turn it on
54: (print 'monitor-on)
55: (terpr))
56: nil)
57: (setq starttime (sys:time) ; real time in seconds
58: startptime (ptime)
59: startgccount $gccount$)
60: (setq in-line-lambda-number (sys:time))
61: (cond ((null (boundp 'internal-macros))
62: (setq internal-macros nil)))
63: (cond ((null (boundp 'macros))
64: (setq macros nil)))
65: (setq er-fatal 0)
66: (setq vps-include nil
67: vns-include nil) ;stack of ports and names
68: (setq twa-list nil)
69: (setq liszt-eof-forms nil)
70:
71: ; look for lisztrc file and return if error occured
72: ; in reading it
73: (cond ((eq (do-lisztrc-check) 'error)
74: (return 1)))
75:
76: ; set up once only g variables
77: (setq g-comments nil
78: g-current nil ; current function name
79: g-funcs nil
80: g-lits nil
81: g-trueloc nil
82: g-tran nil
83: g-allf nil ; used in xrefs
84: g-reguse #+for-vax (copy '((r4 0 . nil) (r3 0 . nil)
85: (r2 0 . nil); (r7 0 . nil)
86: (r1 0 . nil)))
87: #+for-68k (copy '((a0 0 . nil) (a1 0 . nil)
88: (d1 0 . nil) (d2 0 . nil)
89: (d4 0 . nil) (d5 0 . nil)))
90: g-trancnt 0
91: g-ignorereg nil
92: g-trueop #+for-vax 'jneq ; used in e-gotot
93: #+for-68k 'jne
94: g-falseop #+for-vax 'jeql ; used in e-gotonil
95: #+for-68k 'jeq
96: g-compfcn nil
97: g-litcnt 0)
98: (setq g-spec (gensym 'S)) ; flag for special atom
99: (setq g-fname "") ; no function yet
100: (setq special nil) ; t if all vrbs are special
101: (setq g-functype (gensym)
102: g-vartype (gensym)
103: g-bindtype (gensym)
104: g-calltype (gensym)
105: g-bindloc (gensym)
106: g-localf (gensym)
107: g-arrayspecs (gensym)
108: g-tranloc (gensym)
109: g-stdref (gensym)
110: g-optionalp (gensym))
111:
112: ; declare these special
113:
114: (sstatus feature complr)
115: (d-makespec 't) ; always special
116:
117: ; process input form
118: (setq fl-asm t ; assembler file assembled
119: fl-warn t ; print warnings
120: fl-verb t ; be verbose
121: fl-macl nil ; compile maclisp file
122: fl-anno nil ; annotate
123: fl-inter nil ; do interlisp compatablity
124: fl-tty nil ; put .s on tty
125: fl-comments nil ; put in comments
126: fl-profile nil ; profiling
127: fl-tran t ; use transfer tables
128: fl-vms nil ; vms hacks
129: fl-case nil ; trans uc to lc
130: fl-xref nil ; xrefs
131: fl-run nil ; autorun capability
132: fl-uci nil ; uci lisp compatibility
133: )
134:
135: ; look in the environment for a LISZT variable
136: ; if it exists, make it the first argument
137: (if (not (eq '|| (setq tem (getenv 'LISZT))))
138: then (setq v-x (cons (concat "-" tem) v-x)))
139:
140: (do ((i v-x (cdr i))) ; for each argument
141: ((null i))
142: (setq tem (aexplodec (car i)))
143:
144: (cond ((eq '- (car tem)) ; if switch
145: (do ((j (cdr tem) (cdr j)))
146: ((null j))
147: (cond ((eq 'S (car j)) (setq fl-asm nil))
148: ((eq 'C (car j)) (setq fl-comments t))
149: ((eq 'm (car j)) (setq fl-macl t))
150: ((eq 'o (car j)) (setq v-ofile (cadr i)
151: i (cdr i)))
152: ((eq 'e (car j)) (setq pre-eval (cadr i)
153: i (cdr i)))
154: ((eq 'i (car j)) (push (cadr i)
155: include-files)
156: (pop i))
157: ((eq 'w (car j)) (setq fl-warn nil))
158: ((eq 'q (car j)) (setq fl-verb nil))
159: ((eq 'Q (car j)) (setq fl-verb t))
160: ((eq 'T (car j)) (setq fl-tty t))
161: ((eq 'a (car j)) (setq fl-anno t))
162: ((eq 'i (car j)) (setq fl-inter t))
163: ((eq 'p (car j)) (setq fl-profile t))
164: ((eq 'F (car j)) (setq fl-tran nil))
165: ((eq 'v (car j)) (setq fl-vms t))
166: ((eq 'r (car j)) (setq fl-run t))
167: ((eq 'x (car j)) (setq fl-xref t))
168: ((eq 'c (car j)) (setq fl-case t))
169: ((eq 'u (car j)) (setq fl-uci t))
170: ((eq '- (car j))) ; ignore extra -'s
171: (t (comp-gerr "Unknown switch: "
172: (car j))))))
173: ((null v-root)
174: (setq temr (reverse tem))
175: (cond ((and (eq 'l (car temr))
176: (eq '\. (cadr temr)))
177: (setq rootreal nil)
178: (setq v-root
179: (apply 'concat
180: (reverse (cddr temr)))))
181: (t (setq v-root (car i)
182: rootreal t))))
183:
184: (t (comp-gerr "Extra input file name: " (car i)))))
185:
186: ;no transfer tables in vms
187: (cond (fl-vms (setq fl-tran nil)))
188:
189: ; if verbose mode, print out the gc messages and
190: ; fasl messages, else turn them off.
191: (cond (fl-verb (setq $gcprint t
192: $ldprint t))
193: (t (setq $gcprint nil
194: $ldprint nil)))
195:
196: ; eval arg after -e
197: (if pre-eval
198: then (if (null (errset
199: (eval (readlist (exploden pre-eval)))))
200: then (comp-gerr "-e form caused error: "
201: pre-eval)))
202:
203: ; load file after -i arg
204: (if include-files
205: then (catch
206: (mapc
207: '(lambda (file)
208: (if (null (errset (load file)))
209: then (comp-err
210: "error when loading -i file: "
211: file)))
212: include-files)
213: Comp-error))
214:
215: ; -c says set reader to xlate uc to lc
216: (cond (fl-case (sstatus uctolc t)))
217:
218: ; If we are a cross compiler, then don't try to
219: ; assemble our output...
220: ;
221: #+for-vax
222: (if (status feature 68k)
223: then (setq fl-asm nil))
224: #+for-68k
225: (if (status feature vax)
226: then (setq fl-asm nil))
227:
228: ; now see what the arguments have left us
229: (cond ((null v-root)
230: (comp-gerr "No file for input"))
231: ((or (portp
232: (setq vp-ifile
233: (car (errset (infile
234: (setq v-ifile
235: (concat v-root '".l")))
236: nil))))
237: (and rootreal
238: (portp
239: (setq vp-ifile
240: (car (errset
241: (infile (setq v-ifile v-root))
242: nil)))))))
243: (t (comp-gerr "Couldn't open the source file :"
244: (or v-ifile))))
245:
246:
247: ; determine the name of the .s file
248: ; strategy: if fl-asm is t (assemble) use (v-root).s
249: ; else use /tmp/(PID).s
250: ;
251: ; direct asm to tty temporarily
252: (setq v-sfile "tty")
253: (setq vp-sfile nil)
254: (if (null fl-tty) then
255: (cond (fl-asm (setq v-sfile
256: (concat '"/tmp/Lzt"
257: (boole 1 65535
258: (sys:getpid))
259: '".s")))
260: (t (setq v-sfile
261: (if v-ofile
262: then v-ofile
263: else (concat v-root '".s")))))
264:
265: (cond ((not (portp (setq vp-sfile
266: (car (errset (outfile v-sfile)
267: nil)))))
268: (comp-gerr "Couldn't open the .s file: "
269: (or v-sfile)))))
270:
271:
272: ; determine the name of the .o file (object file)
273: ; strategy: if we aren't supposed to assemble the .s file
274: ; don't worry about a name
275: ; else if a name is given, use it
276: ; else if use (v-root).o
277: ; if profiling, use .o
278: (cond ((or v-ofile (null fl-asm))) ;ignore
279: ((null fl-profile) (setq v-ofile (concat v-root ".o")))
280: (t (setq v-ofile (concat v-root ".o"))))
281:
282: ; determine the name of the .x file (xref file)
283: ; strategy: if fl-xref and v-ofile is true, then use
284: ; v-ofile(minus .o).x, else use (v-root).x
285: ;
286: (if fl-xref
287: then ; check for ending with .X for any X
288: (setq v-xfile
289: (if v-ofile
290: then (let ((ex (nreverse
291: (exploden v-ofile))))
292: (if (eq #/. (cadr ex))
293: then (implode
294: (nreverse
295: `(#/x #/.
296: ,@(cddr ex))))
297: else (concat v-ofile ".x")))
298: else (concat v-root ".x")))
299: (if (portp
300: (setq vp-xfile
301: (car (errset (outfile v-xfile)))))
302: thenret
303: else (comp-gerr "Can't open the .x file: "
304: v-xfile)))
305: (cond ((checkfatal) (return 1)))
306:
307: ; g-complrname is a symbol which should be unique to
308: ; each fasl'ed file. It will contain the string which
309: ; describes the name of this file and the compiler
310: ; version.
311: (if fl-anno
312: then (setq g-complrname (concat "fcn-in-" v-ifile))
313: (Push g-funcs
314: `(eval (setq ,g-complrname
315: ,(get_pname
316: (concat v-ifile
317: " compiled by "
318: compiler-name
319: " on "
320: (status ctime)))))))
321:
322:
323: (setq readtable (makereadtable nil)) ; use new readtable
324:
325:
326: ; if the macsyma flag is set, change the syntax to the
327: ; maclisp standard syntax. We must be careful that we
328: ; dont clobber any syntax changes made by files preloaded
329: ; into the compiler.
330:
331: (cond (fl-macl (setsyntax '\/ 'vescape) ; 143 = vesc
332:
333: (cond ((eq 'vescape (getsyntax '\\))
334: (setsyntax '\\ 'vcharacter)))
335:
336: (cond ((eq 'vleft-bracket (getsyntax '\[))
337: (setsyntax '\[ 'vcharacter)
338: (setsyntax '\] 'vcharacter)))
339: (setq ibase 8.)
340: (sstatus uctolc t)
341:
342: (d-makespec 'ibase) ; to be special
343: (d-makespec 'base)
344: (d-makespec 'tty)
345:
346: (errset (cond ((null (getd 'macsyma-env))
347: (load 'machacks)))
348: nil))
349: (fl-uci (load "ucifnc")
350: (cvttoucilisp)))
351:
352: (cond (fl-inter (putprop '* 'cc-ignore 'fl-exprcc) ;comment
353: (remprop '* 'fl-expr)
354: ))
355:
356: (cond ((checkfatal) (return 1))) ; leave if fatal errors
357:
358: (if fl-verb
359: then (comp-msg "Compilation begins with " compiler-name )
360: (comp-msg "source: " v-ifile ", result: "
361: (cond (fl-asm v-ofile) (t v-sfile))))
362:
363: (setq piport vp-ifile) ; set to standard input
364: (setq liszt-root-name v-root
365: liszt-file-name v-ifile)
366:
367:
368: (if fl-run then (d-printautorun))
369:
370: (if fl-profile then (e-write1 '".globl mcount"))
371: loop
372:
373: ; main loop of the compiler. It reads a form and
374: ; compiles it. It continues to compile forms from
375: ; liszt-process-forms was long at that list is
376: ; non-empty. This allows one form to spawn off other
377: ; forms to be compiled (an alternative to (progn 'compile))
378: ;
379: (cond ((atom (errset ; list for debugging,
380: ; errset for production.
381: (do ((i (read piport '<<end-of-file>>)
382: (read piport '<<end-of-file>>)))
383: ((eq i '<<end-of-file>>) nil)
384: (setq liszt-process-forms
385: (cons i liszt-process-forms))
386: (do ((this (car liszt-process-forms)
387: (car liszt-process-forms)))
388: ((null liszt-process-forms))
389: (unpush liszt-process-forms)
390: (catch (liszt-form this) Comp-error)))))
391: (catch (comp-err "Lisp error during compilation")
392: Comp-error)
393: (setq piport nil)
394: (setq er-fatal (1+ er-fatal))
395: (return 1)))
396:
397: (close piport)
398:
399: ; if doing special character stuff (maclisp) reassert
400: ; the state
401:
402: (cond (vps-include
403: (comp-note " done include")
404: (setq piport (car vps-include)
405: vps-include (cdr vps-include)
406: v-ifile (car vns-include)
407: vns-include (cdr vns-include))
408: (go loop)))
409:
410: (cond (liszt-eof-forms
411: (do ((ll liszt-eof-forms (cdr ll)))
412: ((null ll))
413: (cond ((atom (errset (liszt-form (car ll))))
414: (catch
415: (comp-note "Lisp error during eof forms")
416: Comp-error)
417: (setq piport nil)
418: (return 1))))))
419:
420: ; reset input base
421: (setq ibase 10.)
422: (setq readtable (makereadtable t))
423: (sstatus uctolc nil) ; turn off case conversion
424: ; so bindtab will not have |'s
425: ; to quote lower case
426: (d-bindtab)
427:
428: (d-printdocstuff) ; describe this compiler
429:
430: (cond ((portp vp-sfile)
431: (close vp-sfile))) ; close assembler language file
432:
433: ; check for fatal errors and don't leave if so
434: (cond ((checkfatal)
435: (if fl-asm ; unlink .s file
436: then (sys:unlink v-sfile)) ; if it is a tmp
437: (return 1))) ; and ret with error status
438:
439: (comp-note "Compilation complete")
440:
441: (setq tem (Divide (difference (sys:time) starttime) 60))
442: (setq ntem (ptime))
443:
444: (setq temcp (Divide (difference (car ntem) (car startptime))
445: 3600))
446:
447: (setq temgc (Divide (difference (cadr ntem) (cadr startptime))
448: 3600))
449:
450: (comp-note " Time: Real: " (car tem) ":" (cadr tem)
451: ", CPU: " (car temcp) ":" (quotient (cadr temcp) 60.0)
452: ", GC: " (car temgc) ":" (quotient (cadr temgc) 60.0)
453: " for "
454: (difference $gccount$ startgccount)
455: " gcs")
456:
457: (cond (fl-xref
458: (comp-note "Cross reference being generated")
459: (print (list 'File v-ifile) vp-xfile)
460: (terpr vp-xfile)
461: (do ((ii g-allf (cdr ii)))
462: ((null ii))
463: (print (car ii) vp-xfile)
464: (terpr vp-xfile))
465: (close vp-xfile)))
466:
467:
468: ; the assember we use must generate the new a.out format
469: ; with a string table. We will assume that the assembler
470: ; is in /usr/lib/lisp/as so that other sites can run
471: ; the new assembler without installing the new assembler
472: ; as /bin/as
473: (cond (fl-asm ; assemble file
474: (comp-note "Assembly begins")
475: (cond ((not
476: (zerop
477: (setq asm-exit-status
478: (*process
479: (concat
480: lisp-library-directory
481: "/as "
482: #+for-vax "-V" ; use virt mem
483: " -o "
484: v-ofile
485: " "
486: v-sfile)))))
487: (comp-gerr "Assembler detected error, code: "
488: asm-exit-status)
489: (comp-note "Assembler temp file " v-sfile
490: " is not unlinked"))
491: (t (comp-note "Assembly completed successfully")
492: (errset (sys:unlink v-sfile)); unlink tmp
493: ; file
494: (if fl-run
495: then (errset
496: (sys:chmod v-ofile #O775)))))))
497:
498: #+(and sun (not unisoft))
499: (if (and v-ofile fl-run)
500: then (if (null
501: (errset (let ((port (fileopen v-ofile "r+")))
502: (fseek port 20 0)
503: (tyo 0 port)
504: (tyo 0 port)
505: (tyo 128 port)
506: (tyo 0 port)
507: (close port))))
508: then (comp-err
509: "Error while fixing offset in object file: "
510: v-ofile)))
511:
512: (setq readtable original-readtable)
513: #+monitoring
514: (errset (progn (monitor) ; turn off monitoring
515: (print 'monitor-off))
516: nil)
517: (sstatus nofeature complr)
518: (return asm-exit-status))))
519:
520: (def checkfatal
521: (lambda nil
522: (cond ((greaterp er-fatal 0)
523: (catch (comp-err "Compilation aborted due to previous errors")
524: Comp-error)
525: t))))
526:
527: ;--- do-lisztrc-check
528: ; look for a liszt init file named
529: ; .lisztrc or lisztrc or $HOME/.lisztrc or $HOME/lisztrc
530: ; followed by .o or .l or nothing
531: ; return the symbol 'error' if an error occured while reading.
532: ;
533: (defun do-lisztrc-check nil
534: (do ((dirs `("." ,(getenv 'HOME)) (cdr dirs))
535: (val)
536: ($gcprint nil)
537: ($ldprint nil))
538: ((null dirs))
539: (if (setq val
540: (do ((name '(".lisztrc" "lisztrc") (cdr name))
541: (val))
542: ((null name))
543: (if (setq val
544: (do ((ext '(".o" ".l" "") (cdr ext))
545: (file))
546: ((null ext))
547: (if (probef
548: (setq file (concat (car dirs)
549: "/"
550: (car name)
551: (car ext))))
552: then (if (atom (errset (load file)))
553: then (comp-msg
554: "Error loading liszt init file "
555: file N
556: "Compilation aborted" N)
557: (return 'error)
558: else (return t)))))
559: then (return val))))
560: then (return val))))
561:
562:
563: ;--- liszt-form - i : form to compile
564: ; This compiles one form.
565: ;
566: (def liszt-form
567: (lambda (i)
568: (prog (tmp v-x)
569: ; macro expand
570: loop
571: (setq i (d-macroexpand i))
572: ; now look at what is left
573: (cond ((not (dtpr i)) (Push g-funcs `(eval ,i)))
574: ((eq (car i) 'def)
575: (cond (fl-verb (print (cadr i)) (terpr)(drain)))
576: (d-dodef i))
577: ((memq (car i) '(liszt-declare declare))
578: (funcall 'liszt-declare (cdr i)))
579: ((eq (car i) 'eval-when) (doevalwhen i))
580: ((and (eq (car i) 'progn) (equal (cadr i) '(quote compile)))
581: ((lambda (internal-macros) ; compile macros too
582: (mapc 'liszt-form (cddr i)))
583: t))
584: ((or (and (eq (car i) 'includef) (setq tmp (eval (cadr i))))
585: (and (eq (car i) 'include ) (setq tmp (cadr i))))
586: (cond ((or (portp (setq v-x
587: (car (errset (infile tmp) nil))))
588: (portp (setq v-x
589: (car
590: (errset
591: (infile
592: (concat
593: lisp-library-directory
594: "/"
595: tmp))
596: nil))))
597: (portp (setq v-x
598: (car (errset (infile (concat tmp
599: '".l"))
600: nil)))))
601: (setq vps-include (cons piport vps-include))
602: (setq piport v-x)
603: (comp-note " INCLUDEing file: " tmp)
604: (setq vns-include (cons v-ifile vns-include)
605: v-ifile tmp))
606: (t (comp-gerr "Cannot open include file: " tmp))))
607: ((eq (car i) 'comment) nil) ; just ignore comments
608: (t ; we have to macro expand
609: ; certain forms we would normally
610: ; just dump in the eval list. This is due to hacks in
611: ; the mit lisp compiler which are relied upon by certain
612: ; code from mit.
613: (setq i (d-fullmacroexpand i))
614:
615: (Push g-funcs `(eval ,i)))))))
616:
617: ;--- d-dodef :: handle the def form
618: ; - form : a def form: (def name (type args . body))
619: ;
620: (defun d-dodef (form)
621: (prog (g-fname g-ftype g-args body lambdaform symlab g-arginfo
622: g-compfcn g-decls)
623:
624: (setq g-arginfo 'empty)
625:
626: loop
627: ; extract the components of the def form
628: (setq g-fname (cadr form))
629: (if (dtpr (caddr form))
630: then (setq g-ftype (caaddr form)
631: g-args (cadaddr form)
632: body (cddaddr form)
633: lambdaform (caddr form)
634: symlab (gensym 'F))
635: else (comp-gerr "bad def form " form))
636:
637: ; check for a def which uses the mit hackish &xxx forms.
638: ; if seen, convert to a standard form and reexamine
639: ; the vax handles these forms in a special way.
640: #+for-68k
641: (if (or (memq '&rest g-args)
642: (memq '&optional g-args)
643: (memq '&aux g-args))
644: then (setq form
645: `(def ,(cadr form) ,(lambdacvt (cdr lambdaform))))
646: (go loop))
647:
648: ; check for legal function name.
649: ; then look at the type of the function and update the data base.
650: (if (null (atom g-fname))
651: then (comp-err "bad function name")
652: else (setq g-flocal (get g-fname g-localf)) ; check local decl.
653: ; macros are special, they are always evaluated
654: ; and sometimes compiled.
655: (if (and (not g-flocal) (eq g-ftype 'macro))
656: then (eval form)
657: (if (and (null macros)
658: (null internal-macros))
659: then (comp-note g-fname
660: " macro will not be compiled")
661: (return nil))
662: (Push g-funcs `(macro ,symlab ,g-fname))
663: (if fl-anno then (setq g-arginfo nil)) ; no arg info
664: elseif g-flocal
665: then (if (null (or (eq g-ftype 'lambda)
666: (eq g-ftype 'nlambda)))
667: then (comp-err
668: "bad type for local fcn: " g-ftype))
669: (if (or (memq '&rest g-args)
670: (memq '&optional g-args)
671: (memq '&aux g-args))
672: then (comp-err
673: "local functions can't use &keyword's "
674: g-fname))
675: elseif (or (eq g-ftype 'lambda)
676: (eq g-ftype 'lexpr))
677: then (push `(lambda ,symlab ,g-fname) g-funcs)
678: (putprop g-fname 'lambda g-functype)
679: elseif (eq g-ftype 'nlambda)
680: then (Push g-funcs `(nlambda ,symlab ,g-fname))
681: (putprop g-fname 'nlambda g-functype)
682: else (comp-err " bad function type " g-ftype)))
683: (setq g-skipcode nil) ;make sure we aren't skipping code
684: (forcecomment `(fcn ,g-ftype ,g-fname))
685: (if g-flocal
686: then (comp-note g-fname " is a local function")
687: (e-writel (car g-flocal))
688: else (if (null fl-vms) then (e-write2 '".globl" symlab))
689: (e-writel symlab))
690: (setq g-locs nil g-loccnt 0 g-labs nil g-loc 'reg g-cc nil
691: g-ret t g-topsym (d-genlab))
692: (if fl-xref then (setq g-refseen (gensym) g-reflst nil))
693: (d-clearreg)
694: #+for-68k (init-regmaskvec)
695: ; set up global variables which maintain knowledge about
696: ; the stack. these variables are set up as if the correct
697: ; number of args were passed.
698: (setq g-compfcn t) ; now compiling a function
699: (push nil g-labs) ; no labels in a lambda
700: (setq g-currentargs (length g-args))
701: (d-prelude) ; do beginning stuff
702:
703: #+for-vax
704: (d-outerlambdacomp g-fname g-args (cddr lambdaform))
705: #+for-68k
706: (progn
707: (push (cons 'lambda 0) g-locs)
708: (mapc '(lambda (x)
709: (push nil g-locs)
710: (incr g-loccnt))
711: g-args)
712: (d-lambbody lambdaform))
713:
714: (d-fini)
715: (setq g-compfcn nil) ; done compiling a fcn
716: (if fl-xref then
717: (Push g-allf
718: (cons g-fname
719: (cons (cond (g-flocal (cons g-ftype 'local))
720: (t g-ftype))
721: g-reflst))))
722: (if (and fl-anno (not (eq 'empty g-arginfo)))
723: then (Push g-funcs `(eval (putprop
724: ',g-fname
725: (list ',g-arginfo
726: ,g-complrname)
727: 'fcn-info))))
728: ; by storing argument count information during compilation
729: ; we can arg number check calls to this function which occur
730: ; further on.
731: (if (not (eq 'empty g-arginfo))
732: then (putprop g-fname (list g-arginfo) 'fcn-info))))
733:
734: ;--- d-lambdalistcheck :: scan lambda var list for & forms
735: ; return
736: ; (required optional rest op-p body)
737: ; required - list of required args
738: ; optional - list of (variable default [optional-p])
739: ; rest - either nil or the name of a variable for optionals
740: ; op-p - list of variables set to t or nil depending if optional exists
741: ; body - body to compile (has &aux's wrapped around it in lambdas)
742: ;
743: #+for-vax
744: (defun d-lambdalistcheck (list body)
745: (do ((xx list (cdr xx))
746: (state 'req)
747: (statechange)
748: (arg)
749: (req)(optional)(rest)(op-p)(aux))
750: ((null xx)
751: (list (nreverse req)
752: (nreverse optional)
753: rest
754: (nreverse op-p)
755: (d-lambda-aux-body-convert body (nreverse aux))))
756: (setq arg (car xx))
757: (if (memq arg '(&optional &rest &aux))
758: then (setq statechange arg)
759: else (setq statechange nil))
760: (caseq state
761: (req
762: (if statechange
763: then (setq state statechange)
764: elseif (and (symbolp arg) arg)
765: then (push arg req)
766: else (comp-err " illegal lambda variable " arg)))
767: (&optional
768: (if statechange
769: then (if (memq statechange '(&rest &aux))
770: then (setq state statechange)
771: else (comp-err "illegal form in lambda list "
772: xx))
773: elseif (symbolp arg)
774: then ; optional which defaults to nil
775: (push (list arg nil) optional)
776: elseif (dtpr arg)
777: then (if (and (symbolp (car arg))
778: (symbolp (caddr arg)))
779: then ; optional with default
780: (push arg optional)
781: ; save op-p
782: (if (cddr arg)
783: then (push (caddr arg) op-p)))
784: else (comp-err "illegal &optional form "
785: arg)))
786: (&rest
787: (if statechange
788: then (if (eq statechange '&aux)
789: then (setq state statechange)
790: else (comp-err "illegal lambda variable form "
791: xx))
792: elseif rest
793: then (comp-err
794: "more than one rest variable in lambda list"
795: arg)
796: else (setq rest arg)))
797: (&aux
798: (if statechange
799: then (comp-err "illegal lambda form " xx)
800: elseif (and (symbolp arg) arg)
801: then (push (list arg nil) aux)
802: elseif (and (dtpr arg) (and (symbolp (car arg))
803: (car arg)))
804: then (push arg aux)))
805: (t (comp-err "bizzarro internal compiler error ")))))
806:
807: ;--- d-lambda-aux-body-convert :: convert aux's to lambdas
808: ; give a function body and a list of aux variables
809: ; and their inits, place a lambda initializing body around body
810: ; for each lambda (basically doing a let*).
811: ;
812: #+for-vax
813: (defun d-lambda-aux-body-convert (body auxlist)
814: (if (null auxlist)
815: then body
816: else `(((lambda (,(caar auxlist))
817: ,@(d-lambda-aux-body-convert body (cdr auxlist)))
818: ,(cadar auxlist)))))
819:
820: ;--- d-outerlambdacomp :: compile a functions outer lambda body
821: ; This function compiles the lambda expression which defines
822: ; the function. This lambda expression differs from the kind that
823: ; appears within a function because
824: ; 1. we aren't sure that the correct number of arguments have been stacked
825: ; 2. the keywords &optional, &rest, and &aux may appear
826: ;
827: ; funname - name of function
828: ; lambdalist - the local argument list, (with possible keywords)
829: ; body - what follows the lambdalist
830: ;
831: ;
832: ;
833: #+for-vax
834: (defun d-outerlambdacomp (funname lambdalist body)
835: (let (((required optional rest op-p newbody)
836: (d-lambdalistcheck lambdalist body))
837: (g-decls g-decls)
838: (reqnum 0) maxwithopt labs (maxnum -1) args)
839: (d-scanfordecls body)
840: ; if this is a declared lexpr, we aren't called
841: ;
842: (if (and (null optional) (null rest))
843: then ; simple, the number of args is required
844: ; if lexpr or local function, then don't bother
845: (if (and (not g-flocal)
846: (not (eq g-ftype 'lexpr)))
847: then (d-checkforfixedargs
848: funname
849: (setq reqnum (setq maxnum (length required)))))
850: else ; complex, unknown number of args
851: ; cases:
852: ; optional, no rest
853: ; optional, with rest
854: ; no optional, rest + required
855: ; no optional, rest + no required
856: (setq reqnum (length required)
857: maxwithopt (+ reqnum (length optional))
858: maxnum (if rest then -1 else maxwithopt))
859: ; determine how many args were given
860: (e-sub3 '#.lbot-reg '#.np-reg '#.lbot-reg)
861: (e-write4 'ashl '$-2 '#.lbot-reg '#.lbot-reg)
862: ;
863: (if (null optional)
864: then ; just a rest
865: (let ((oklab (d-genlab))
866: (lllab (d-genlab))
867: (nopushlab (d-genlab)))
868: (if (> reqnum 0)
869: then (e-cmp '#.lbot-reg `($ ,reqnum))
870: (e-write2 'jgeq oklab)
871: ; not enough arguments given
872: (d-wnaerr funname reqnum -1)
873: (e-label oklab))
874: (e-pushnil 1)
875: (if (> reqnum 0)
876: then (e-sub `($ ,reqnum) '#.lbot-reg)
877: else (e-tst '#.lbot-reg))
878: (e-write2 'jleq nopushlab)
879: (e-label lllab)
880: (e-quick-call '_qcons)
881: (d-move 'reg 'stack)
882: (e-write3 'sobgtr '#.lbot-reg lllab)
883: (e-label nopushlab))
884: else ; has optional args
885: ; need one label for each optional plus 2
886: (do ((xx optional (cdr xx))
887: (res (list (d-genlab) (d-genlab))))
888: ((null xx) (setq labs res))
889: (push (d-genlab) res))
890: ; push nils for missing optionals
891: ; one case for required amount and one for
892: ; each possible number of optionals
893: (e-write4 'casel
894: '#.lbot-reg `($ ,reqnum)
895: `($ ,(- maxwithopt reqnum)))
896: (e-label (car labs))
897: (do ((xx (cdr labs) (cdr xx))
898: (head (car labs)))
899: ((null xx))
900: (e-write2 '.word (concat (car xx) "-" head)))
901: ; get here (when running code) if there are more
902: ; than the optional number of args or if there are
903: ; too few args. If &rest is given, it is permitted
904: ; to have more than the required number
905: (let ((dorest (d-genlab))
906: (again (d-genlab))
907: (afterpush (d-genlab)))
908: (if rest
909: then ; check if there are greater than
910: ; the required number
911: ; preserve arg #
912: (C-push '#.lbot-reg)
913: (e-sub2 `($ ,maxwithopt) '#.lbot-reg)
914: (e-write2 'jgtr dorest)
915: (C-pop '#.lbot-reg))
916: ; wrong number of args
917: (d-wnaerr funname reqnum maxnum)
918: (if rest
919: then ; now cons the rest forms
920: (e-label dorest)
921: (e-pushnil 1) ; list ends with nil
922: (e-label again)
923: (e-quick-call '_qcons)
924: (d-move 'reg 'stack)
925: ; and loop
926: (e-write3 'sobgtr '#.lbot-reg again)
927: ; arg #
928: (C-pop '#.lbot-reg)
929: (e-goto afterpush))
930: ; push the nils on the optionals
931: (do ((xx (cdr labs) (cdr xx)))
932: ((null xx))
933: (e-label (car xx))
934: ; if we have exactly as many arguments given
935: ; as the number of optionals, then we stack
936: ; a nil if there is a &rest after
937: ; the optionals
938: (if (null (cdr xx))
939: then (if rest
940: then (e-pushnil 1))
941: else (e-pushnil 1)))
942: (e-label afterpush))))
943: ; for optional-p's stack t's
944: (mapc '(lambda (form) (d-move 'T 'stack)) op-p)
945:
946: ; now the variables must be shallow bound
947: ; creat a list of all arguments
948: (setq args (append required
949: (mapcar 'car optional)
950: (if rest then (list rest))
951: op-p))
952:
953: (push (cons 'lambda 0) g-locs)
954: (mapc '(lambda (x)
955: (push nil g-locs))
956: args)
957: (setq g-loccnt (length args))
958: (d-bindlamb args) ; do shallow binding if necessary
959: ;
960: ; if any of the optionals have non null defaults or
961: ; optional-p's, we have to evaluate their defaults
962: ; or set their predicates.
963: ; first, see if it is necessary
964: (if (do ((xx optional (cdr xx)))
965: ((null xx) nil)
966: (if (or (cadar xx) ; if non null default
967: (caddar xx)); or predicate
968: then (return t)))
969: then (makecomment '(do optional defaults and preds))
970: ; create labels again
971: ; need one label for each optional plus 1
972: (do ((xx optional (cdr xx))
973: (res (list (d-genlab) )))
974: ((null xx) (setq labs res))
975: (push (d-genlab) res))
976: ; we need to do something if the argument count
977: ; is between the number of required arguments and
978: ; the maximum number of args with optional minus 1.
979: ; we have one case for the required number and
980: ; one for each optional except the last optional number
981: ;
982: (let ((afterthis (d-genlab)))
983: (e-write4 'casel
984: '#.lbot-reg `($ ,reqnum)
985: `($ ,(- maxwithopt reqnum 1)))
986: (e-label (car labs))
987: (do ((xx (cdr labs) (cdr xx))
988: (head (car labs)))
989: ((null xx))
990: (e-write2 '.word (concat (car xx) "-" head)))
991: (e-goto afterthis)
992: (do ((ll (cdr labs) (cdr ll))
993: (op optional (cdr op))
994: (g-loc nil)
995: (g-cc nil)
996: (g-ret nil))
997: ((null ll))
998: (e-label (car ll))
999: (if (caddar op)
1000: then (d-exp `(setq ,(caddar op) nil)))
1001: (if (cadar op)
1002: then (d-exp `(setq ,(caar op) ,(cadar op)))))
1003: (e-label afterthis)))
1004:
1005: ; now compile the function
1006: (d-clearreg)
1007: (setq g-arginfo
1008: (if (eq g-ftype 'nlambda)
1009: then nil
1010: else (cons reqnum (if (>& maxnum 0) then maxnum else nil))))
1011: (makecomment '(begin-fcn-body))
1012: (d-exp (do ((ll newbody (cdr ll))
1013: (g-loc)
1014: (g-cc)
1015: (g-ret))
1016: ((null (cdr ll)) (car ll))
1017: (d-exp (car ll))))
1018: (d-unbind)))
1019:
1020: #+for-vax
1021: (defun d-checkforfixedargs (fcnname number)
1022: (let ((oklab (d-genlab)))
1023: (makecomment `(,fcnname should-have-exactly ,number args))
1024: ; calc -4*# of args
1025: (e-sub '#.np-reg '#.lbot-reg)
1026: (e-cmp '#.lbot-reg `($ ,(- (* number 4))))
1027: (e-write2 'jeql oklab)
1028: (d-wnaerr fcnname number number)
1029: (e-label oklab)))
1030:
1031: ;--- d-wnaerr :: generate code to call wrong number of args error
1032: ; name is the function name,
1033: ; min is the minumum number of args for this function
1034: ; max is the maximum number (-1 if there is no maximum)
1035: ; we encode the min and max in the way shown below.
1036: ;
1037: #+for-vax
1038: (defun d-wnaerr (name min max)
1039: (makecomment `(arg error for fcn ,name min ,min max ,max))
1040: (e-move 'r10 '#.lbot-reg)
1041: (C-push `($ ,(+ (* min 1000) (+ max 1))))
1042: (C-push (e-cvt (d-loclit name nil)))
1043: (e-write3 'calls '$2 '_wnaerr))
1044:
1045: ;--- d-genlab :: generate a pseudo label
1046: ;
1047: (defun d-genlab nil
1048: (gensym 'L))
1049:
1050: ;--- liszt-interrupt-signal
1051: ; if we receive a interrupt signal (commonly a ^C), then
1052: ; unlink the .s file if we are generating a temporary one
1053: ; and exit
1054: (defun liszt-interrupt-signal (sig)
1055: (if (and fl-asm (boundp 'v-sfile) v-sfile)
1056: then (sys:unlink v-sfile))
1057: (exit 1))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.