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