OSDN Git Service

* cos.scm (/object-debug-classes): Delete.
[pf3gnuchains/pf3gnuchains3x.git] / cgen / utils.scm
1 ; Generic Utilities.
2 ; Copyright (C) 2000, 2005, 2006, 2007, 2009 Red Hat, Inc.
3 ; This file is part of CGEN.
4 ; See file COPYING.CGEN for details.
5
6 ; These utilities are neither object nor cgen centric.
7 ; They're generic, non application-specific utilities.
8 ; There are a few exceptions, keep them to a minimum.
9 ;
10 ; Conventions:
11 ; - the prefix "gen-" comes from cgen's convention that procs that return C
12 ;   code, and only those procs, are prefixed with "gen-"
13
14 (define nil '())
15
16 ; Hobbit support code; for when not using hobbit.
17 ; FIXME: eliminate this stuff ASAP.
18
19 (defmacro /fastcall-make (proc) proc)
20
21 (defmacro fastcall4 (proc arg1 arg2 arg3 arg4)
22   (list proc arg1 arg2 arg3 arg4)
23 )
24
25 (defmacro fastcall5 (proc arg1 arg2 arg3 arg4 arg5)
26   (list proc arg1 arg2 arg3 arg4 arg5)
27 )
28
29 (defmacro fastcall6 (proc arg1 arg2 arg3 arg4 arg5 arg6)
30   (list proc arg1 arg2 arg3 arg4 arg5 arg6)
31 )
32
33 (defmacro fastcall7 (proc arg1 arg2 arg3 arg4 arg5 arg6 arg7)
34   (list proc arg1 arg2 arg3 arg4 arg5 arg6 arg7)
35 )
36
37 ; Value doesn't matter too much here, just ensure it's portable.
38 (define *UNSPECIFIED* (if #f 1))
39
40 (define assert-fail-msg "assertion failure:")
41
42 (defmacro assert (expr)
43   `(if (not ,expr)
44        (error assert-fail-msg ',expr))
45 )
46
47 (define verbose-level 0)
48
49 (define (verbose-inc!)
50   (set! verbose-level (+ verbose-level 1))
51 )
52
53 (define (verbose? level) (>= verbose-level level))
54
55 ; Print to stderr, takes an arbitrary number of objects, possibly nested.
56 ; ??? Audit callers, can we maybe just use "display" here (except that
57 ; we still might want some control over the output).
58
59 (define message
60   (lambda args
61     (for-each (lambda (str)
62                 (if (pair? str)
63                     (if (list? str)
64                         ;; ??? Incorrect for improper lists, later.
65                         (begin
66                           (message "(")
67                           (for-each (lambda (s) (message s " ")) str)
68                           (message ")"))
69                         (message "(" (car str) " . " (cdr str) ")"))
70                     (display str (current-error-port))))
71               args))
72 )
73
74 ; Print a message if the verbosity level calls for it.
75 ; This is a macro as a bit of cpu may be spent computing args,
76 ; and we only want to spend it if the result will be printed.
77
78 (defmacro logit (level . args)
79   `(if (>= verbose-level ,level) (message ,@args))
80 )
81
82 ; Return a string of N spaces.
83
84 (define (spaces n) (make-string n #\space))
85
86 ; Write N spaces to PORT, or the current output port if elided.
87
88 (define (write-spaces n . port)
89   (let ((port (if (null? port) (current-output-port) (car port))))
90     (write (spaces n) port))
91 )
92
93 ; Concatenate all the arguments and make a string.  Symbols are
94 ; converted to strings.
95 (define (string/symbol-append . sequences)
96   (define (sequence->string o) (if (symbol? o) (symbol->string o) o))
97   (apply string-append (map sequence->string sequences)))
98
99 ; Often used idiom.
100
101 (define (string-map fn . args) (apply string-append (apply map (cons fn args))))
102
103 ; Collect a flat list of returned sublists from the lambda fn applied over args.
104
105 (define (collect fn . args) (apply append (apply map (cons fn args))))
106
107 ; Map over value entries in an alist.
108 ; 'twould be nice if this were a primitive.
109
110 (define (amap fn args)
111   (map fn (map cdr args))
112 )
113
114 ; Like map but accept a proper or improper list.
115 ; An improper list is (a b c . d).
116 ; FN must be a proc of one argument.
117
118 (define (map1-improper fn l)
119   (let ((result nil))
120     (let loop ((last #f) (l l))
121       (cond ((null? l)
122              result)
123             ((pair? l)
124              (if last
125                  (begin
126                    (set-cdr! last (cons (fn (car l)) nil))
127                    (loop (cdr last) (cdr l)))
128                  (begin
129                    (set! result (cons (fn (car l)) nil))
130                    (loop result (cdr l)))))
131             (else
132              (if last
133                  (begin
134                    (set-cdr! last (fn l))
135                    result)
136                  (fn l))))))
137 )
138
139 ; Turn string or symbol STR into a proper C symbol.
140 ; The result is a string.
141 ; We assume STR has no leading digits.
142 ; All invalid characters are turned into '_'.
143 ; FIXME: Turn trailing "?" into "_p".
144
145 (define (gen-c-symbol str)
146   (if (not (or (string? str) (symbol? str)))
147       (error "gen-c-symbol: not symbol or string:" str))
148   (map-over-string (lambda (c) (if (id-char? c) c #\_))
149                    (->string str))
150 )
151
152 ; Turn string or symbol STR into a proper file name, which is
153 ; defined to be the same as gen-c-symbol except use -'s instead of _'s.
154 ; The result is a string.
155
156 (define (gen-file-name str)
157   (if (not (or (string? str) (symbol? str)))
158       (error "gen-file-name: not symbol or string:" str))
159   (map-over-string (lambda (c) (if (id-char? c) c #\-))
160                    (->string str))
161 )
162
163 ; Turn STR into lowercase.
164
165 (define (string-downcase str)
166   (map-over-string (lambda (c) (char-downcase c)) str)
167 )
168
169 ; Turn STR into uppercase.
170
171 (define (string-upcase str)
172   (map-over-string (lambda (c) (char-upcase c)) str)
173 )
174
175 ; Turn SYM into lowercase.
176
177 (define (symbol-downcase sym)
178   (string->symbol (string-downcase (symbol->string sym)))
179 )
180
181 ; Turn SYM into uppercase.
182
183 (define (symbol-upcase sym)
184   (string->symbol (string-upcase (symbol->string sym)))
185 )
186
187 ; Symbol sorter.
188
189 (define (symbol<? a b)
190   (string<? (symbol->string a) (symbol->string b))
191 )
192
193 ; Drop N chars from string S.
194 ; If N is negative, drop chars from the end.
195 ; It is ok to drop more characters than are in the string, the result is "".
196
197 (define (string-drop n s)
198   (cond ((>= n (string-length s)) "")
199         ((< n 0) (substring s 0 (+ (string-length s) n)))
200         (else (substring s n (string-length s))))
201 )
202
203 ; Drop the leading char from string S (assumed to have at least 1 char).
204
205 (define (string-drop1 s)
206   (string-drop 1 s)
207 )
208
209 ; Return the leading N chars from string STR.
210 ; This has APL semantics:
211 ; N > length: FILLER chars are appended
212 ; N < 0: take from the end of the string and prepend FILLER if necessary
213
214 (define (string-take-with-filler n str filler)
215   (let ((len (string-length str)))
216     (if (< n 0)
217         (let ((n (- n)))
218           (string-append (if (> n len)
219                              (make-string (- n len) filler)
220                              "")
221                          (substring str (max 0 (- len n)) len)))
222         (string-append (substring str 0 (min len n))
223                        (if (> n len)
224                            (make-string (- n len) filler)
225                            ""))))
226 )
227
228 (define (string-take n str)
229   (string-take-with-filler n str #\space)
230 )
231
232 ; Return the leading char from string S (assumed to have at least 1 char).
233
234 (define (string-take1 s)
235   (substring s 0 1)
236 )
237
238 ; Return the index of char C in string S or #f if not found.
239
240 (define (string-index s c)
241   (let loop ((i 0))
242     (cond ((= i (string-length s)) #f)
243           ((char=? c (string-ref s i)) i)
244           (else (loop (1+ i)))))
245 )
246
247 ; Cut string S into a list of strings using delimiter DELIM (a character).
248
249 (define (string-cut s delim)
250   (let loop ((start 0)
251              (end 0)
252              (length (string-length s))
253              (result nil))
254     (cond ((= end length)
255            (if (> end start)
256                (reverse! (cons (substring s start end) result))
257                (reverse! result)))
258           ((char=? (string-ref s end) delim)
259            (loop (1+ end) (1+ end) length (cons (substring s start end) result)))
260           (else (loop start (1+ end) length result))))
261 )
262
263 ; Convert a list of elements to a string, inserting DELIM (a string)
264 ; between elements.
265 ; L can also be a string or a number.
266
267 (define (stringize l delim)
268   (cond ((string? l) l)
269         ((number? l) (number->string l))
270         ((symbol? l) (symbol->string l))
271         ((list? l)
272          (string-drop
273           (string-length delim)
274           (string-map (lambda (elm)
275                         (string-append delim
276                                        (stringize elm delim)))
277                       l)))
278         (else (error "stringize: can't handle:" l)))
279 )
280
281 ; Same as string-append, but accepts symbols too.
282 ; PERF: This implementation may be unacceptably slow.  Revisit.
283
284 (define stringsym-append
285   (lambda args
286     (apply string-append
287            (map (lambda (s)
288                   (if (symbol? s)
289                       (symbol->string s)
290                       s))
291                 args)))
292 )
293
294 ; Same as symbol-append, but accepts strings too.
295
296 (define symbolstr-append
297   (lambda args
298     (string->symbol (apply stringsym-append args)))
299 )
300
301 ; Given a symbol or a string, return the string form.
302
303 (define (->string s)
304   (if (symbol? s)
305       (symbol->string s)
306       s)
307 )
308
309 ; Given a symbol or a string, return the symbol form.
310
311 (define (->symbol s)
312   (if (string? s)
313       (string->symbol s)
314       s)
315 )
316 \f
317 ; Output routines.
318
319 ;; Given some state that has a setter function (SETTER NEW-VALUE) and
320 ;; a getter function (GETTER), call THUNK with the state set to VALUE,
321 ;; and restore the original value when THUNK returns.  Ensure that the
322 ;; original value is restored whether THUNK returns normally, throws
323 ;; an exception, or invokes a continuation that leaves the call's
324 ;; dynamic scope.
325
326 (define (setter-getter-fluid-let setter getter value thunk)
327   (let ((swap (lambda ()
328                 (let ((temp (getter)))
329                   (setter value)
330                   (set! value temp)))))
331     (dynamic-wind swap thunk swap)))
332       
333
334 ;; Call THUNK with the current input and output ports set to PORT, and
335 ;; then restore the current ports to their original values.
336 ;; 
337 ;; This ensures the current ports get restored whether THUNK exits
338 ;; normally, throws an exception, or leaves the call's dynamic scope
339 ;; by applying a continuation.
340
341 (define (with-input-and-output-to port thunk)
342   (setter-getter-fluid-let
343    set-current-input-port current-input-port port
344    (lambda ()
345      (setter-getter-fluid-let
346       set-current-output-port current-output-port port
347       thunk))))
348
349
350 ; Extension to the current-output-port.
351 ; Only valid inside string-write.
352
353 (define /current-print-state #f)
354
355 ; Create a print-state object.
356 ; This is written in portable Scheme so we don't use COS objects, etc.
357
358 (define (make-print-state)
359   (vector 'print-state 0)
360 )
361
362 ; print-state accessors.
363
364 (define (pstate-indent pstate) (vector-ref pstate 1))
365 (define (pstate-set-indent! pstate indent) (vector-set! pstate 1 indent))
366
367 ; Special print commands (embedded in args).
368
369 (define (pstate-cmd? x) (and (vector? x) (eq? (vector-ref x 0) 'pstate)))
370
371 ;(define /endl (vector 'pstate '/endl)) ; ??? needed?
372 (define /indent (vector 'pstate '/indent))
373 (define (/indent-set n) (vector 'pstate '/indent-set n))
374 (define (/indent-add n) (vector 'pstate '/indent-add n))
375
376 ; Process a pstate command.
377
378 (define (pstate-cmd-do pstate cmd)
379   (assert (pstate-cmd? cmd))
380   (case (vector-ref cmd 1)
381     ((/endl)
382      "\n")
383     ((/indent)
384      (let ((indent (pstate-indent pstate)))
385        (string-append (make-string (quotient indent 8) #\tab)
386                       (make-string (remainder indent 8) #\space))))
387     ((/indent-set)
388      (pstate-set-indent! pstate (vector-ref cmd 2))
389      "")
390     ((/indent-add)
391      (pstate-set-indent! pstate (+ (pstate-indent pstate)
392                                    (vector-ref cmd 2)))
393      "")
394     (else
395      (error "unknown pstate command" (vector-ref cmd 1))))
396 )
397
398 ; Write STRINGS to current-output-port.
399 ; STRINGS is a list of things to write.  Supported types are strings, symbols,
400 ; lists, procedures.  Lists are printed by applying string-write recursively.
401 ; Procedures are thunks that return the string to write.
402 ;
403 ; The result is the empty string.  This is for debugging where this
404 ; procedure is modified to return its args, rather than write them out.
405
406 (define string-write
407   (lambda strings
408     (let ((pstate (make-print-state)))
409       (set! /current-print-state pstate)
410       (for-each (lambda (elm) (/string-write pstate elm))
411                 strings)
412       (set! /current-print-state #f)
413       ""))
414 )
415
416 ; Subroutine of string-write and string-write-map.
417
418 (define (/string-write pstate expr)
419   (cond ((string? expr) (display expr)) ; not write, we want raw text
420         ((symbol? expr) (display expr))
421         ((procedure? expr) (/string-write pstate (expr)))
422         ((pstate-cmd? expr) (display (pstate-cmd-do pstate expr)))
423         ((list? expr) (for-each (lambda (x) (/string-write pstate x)) expr))
424         (else (error "string-write: bad arg:" expr)))
425   *UNSPECIFIED*
426 )
427
428 ; Combination of string-map and string-write.
429
430 (define (string-write-map proc arglist)
431   (let ((pstate /current-print-state))
432     (for-each (lambda (arg) (/string-write pstate (proc arg)))
433               arglist))
434   ""
435 )
436
437 ; Build up an argument for string-write.
438
439 (define string-list list)
440 (define string-list-map map)
441
442 ; Subroutine of string-list->string.  Does same thing /string-write does.
443
444 (define (/string-list-flatten pstate strlist)
445   (cond ((string? strlist) strlist)
446         ((symbol? strlist) strlist)
447         ((procedure? strlist) (/string-list-flatten pstate (strlist)))
448         ((pstate-cmd? strlist) (pstate-cmd-do pstate strlist))
449         ((list? strlist) (apply string-append
450                                 (map (lambda (str)
451                                        (/string-list-flatten pstate str))
452                                      strlist)))
453         (else (error "string-list->string: bad arg:" strlist)))
454 )
455
456 ; Flatten out a string list.
457
458 (define (string-list->string strlist)
459   (/string-list-flatten (make-print-state) strlist)
460 )
461 \f
462 ; Prefix CHARS, a string of characters, with backslash in STR.
463 ; STR is either a string or list of strings (to any depth).
464 ; ??? Quick-n-dirty implementation.
465
466 (define (backslash chars str)
467   (if (string? str)
468       ; quick check for any work to do
469       (if (any-true? (map (lambda (c)
470                             (string-index str c))
471                           (string->list chars)))
472           (let loop ((result "") (str str))
473             (if (= (string-length str) 0)
474                 result
475                 (loop (string-append result
476                                      (if (string-index chars (string-ref str 0))
477                                          "\\"
478                                          "")
479                                      (substring str 0 1))
480                       (substring str 1 (string-length str)))))
481           str)
482       ; must be a list
483       (if (null? str)
484           nil
485           (cons (backslash chars (car str))
486                 (backslash chars (cdr str)))))
487 )
488
489 ; Return a boolean indicating if S is bound to a value.
490 ;(define old-symbol-bound? symbol-bound?)
491 ;(define (symbol-bound? s) (old-symbol-bound? #f s))
492
493 ; Return a boolean indicating if S is a symbol and is bound to a value.
494
495 (define (bound-symbol? s)
496   (and (symbol? s)
497        (or (symbol-bound? #f s)
498            ;(module-bound? cgen-module s)
499            ))
500 )
501
502 ; Return X.
503
504 (define (identity x) x)
505
506 ; Test whether X is a `form' (non-empty list).
507 ; ??? Is `form' the right word to use here?
508 ; One can argue we should also test for a valid car.  If so, it's the
509 ; name that's wrong not the code (because the code is what I want).
510
511 (define (form? x) (and (not (null? x)) (list? x)))
512
513 ; Return the number of arguments to ARG-SPEC, a valid argument list
514 ; of `lambda'.
515 ; The result is a pair: number of fixed arguments, varargs indicator (#f/#t).
516
517 (define (num-args arg-spec)
518   (if (symbol? arg-spec)
519       '(0 . #t)
520       (let loop ((count 0) (arg-spec arg-spec))
521         (cond ((null? arg-spec) (cons count #f))
522               ((null? (cdr arg-spec)) (cons (+ count 1) #f))
523               ((pair? (cdr arg-spec)) (loop (+ count 1) (cdr arg-spec)))
524               (else (cons (+ count 1) #t)))))
525 )
526
527 ; Return a boolean indicating if N args is ok to pass to a proc with
528 ; an argument specification of ARG-SPEC (a valid argument list of `lambda').
529
530 (define (num-args-ok? n arg-spec)
531   (let ((processed-spec (num-args arg-spec)))
532     (and
533      ; Ensure enough fixed arguments.
534      (>= n (car processed-spec))
535      ; If more args than fixed args, ensure varargs.
536      (or (= n (car processed-spec))
537          (cdr processed-spec))))
538 )
539
540 ; Take N elements from list L.
541 ; If N is negative, take elements from the end.
542 ; If N is larger than the length, the extra elements are NIL.
543 ; FIXME: incomplete
544 ; FIXME: list-tail has args reversed (we should conform)
545
546 (define (list-take n l)
547   (let ((len (length l)))
548     (if (< n 0)
549         (list-tail l (+ len n))
550         (let loop ((result nil) (l l) (i 0))
551           (if (= i n)
552               (reverse! result)
553               (loop (cons (car l) result) (cdr l) (+ i 1))))))
554 )
555
556 ; Drop N elements from list L.
557 ; FIXME: list-tail has args reversed (we should conform)
558
559 (define (list-drop n l)
560   (let loop ((n n) (l l))
561     (if (> n 0)
562         (loop (- n 1) (cdr l))
563         l))
564 )
565
566 ; Drop N elements from the end of L.
567 ; FIXME: list-tail has args reversed (we should conform)
568
569 (define (list-tail-drop n l)
570   (reverse! (list-drop n (reverse l)))
571 )
572
573 ;; left fold
574
575 (define (foldl kons accum lis) 
576   (if (null? lis) accum 
577       (foldl kons (kons accum (car lis)) (cdr lis))))
578
579 ;; right fold
580
581 (define (foldr kons knil lis) 
582   (if (null? lis) knil 
583       (kons (car lis) (foldr kons knil (cdr lis)))))
584
585 ;; filter list on predicate
586
587 (define (filter p ls)
588   (foldr (lambda (x a) (if (p x) (cons x a) a)) 
589          '() ls))
590
591 ; APL's +\ operation on a vector of numbers.
592
593 (define (plus-scan l)
594   (letrec ((-plus-scan (lambda (l result)
595                          (if (null? l)
596                              result
597                              (-plus-scan (cdr l)
598                                          (cons (if (null? result)
599                                                    (car l)
600                                                    (+ (car l) (car result)))
601                                                result))))))
602     (reverse! (-plus-scan l nil)))
603 )
604
605 ; Remove duplicate elements from sorted list L.
606 ; Currently supported elements are symbols (a b c) and lists ((a) (b) (c)).
607 ; NOTE: Uses equal? for comparisons.
608
609 (define (remove-duplicates l)
610   (let loop ((l l) (result nil))
611     (cond ((null? l) (reverse! result))
612           ((null? result) (loop (cdr l) (cons (car l) result)))
613           ((equal? (car l) (car result)) (loop (cdr l) result))
614           (else (loop (cdr l) (cons (car l) result)))
615           )
616     )
617 )
618
619 ; Return a boolean indicating if each element of list satisfies its
620 ; corresponding predicates.  The length of L must be equal to the length
621 ; of PREDS.
622
623 (define (list-elements-ok? l preds)
624   (and (list? l)
625        (= (length l) (length preds))
626        (all-true? (map (lambda (pred elm) (pred elm)) preds l)))
627 )
628
629 ; Remove duplicates from unsorted list L.
630 ; KEY-GENERATOR is a lambda that takes a list element as input and returns
631 ; an equal? key to use to determine duplicates.
632 ; The first instance in a set of duplicates is always used.
633 ; This is not intended to be applied to large lists with an expected large
634 ; result (where sorting the list first would be faster), though one could
635 ; add such support later.
636 ;
637 ; ??? Rename to follow memq/memv/member naming convention.
638
639 (define (nub l key-generator)
640   (let loop ((l l) (keys (map key-generator l)) (result nil))
641     (if (null? l)
642         (reverse! (map cdr result))
643         (if (assv (car keys) result)
644             (loop (cdr l) (cdr keys) result)
645             (loop (cdr l) (cdr keys) (acons (car keys) (car l)
646                                              result)))))
647 )
648
649 ; Return a boolean indicating if list L1 is a subset of L2.
650 ; Uses memq.
651
652 (define (subset? l1 l2)
653   (let loop ((l1 l1))
654     (if (null? l1)
655         #t
656         (if (memq (car l1) l2)
657             (loop (cdr l1))
658             #f)))
659 )
660
661 ; Return intersection of two lists.
662
663 (define (intersection a b) 
664   (foldl (lambda (l e) (if (memq e a) (cons e l) l)) '() b))
665
666 ; Return union of two lists.
667
668 (define (union a b) 
669   (foldl (lambda (l e) (if (memq e l) l (cons e l))) a b))
670
671 ; Return a count of the number of elements of list L1 that are in list L2.
672 ; Uses memq.
673
674 (define (count-common l1 l2)
675   (let loop ((result 0) (l1 l1))
676     (if (null? l1)
677         result
678         (if (memq (car l1) l2)
679             (loop (+ result 1) (cdr l1))
680             (loop result (cdr l1)))))
681 )
682
683 ; Remove duplicate elements from sorted alist L.
684 ; L must be sorted by name.
685
686 (define (alist-nub l)
687   (let loop ((l l) (result nil))
688     (cond ((null? l) (reverse! result))
689           ((null? result) (loop (cdr l) (cons (car l) result)))
690           ((eq? (caar l) (caar result)) (loop (cdr l) result))
691           (else (loop (cdr l) (cons (car l) result)))
692           )
693     )
694 )
695
696 ; Return a copy of alist L.
697
698 (define (alist-copy l)
699   ; (map cons (map car l) (map cdr l)) ; simple way
700   ; presumably more efficient way (less cons cells created)
701   (map (lambda (elm)
702          (cons (car elm) (cdr elm)))
703        l)
704 )
705
706 ; Return the order in which to select elements of L sorted by SORT-FN.
707 ; The result is origin 0.
708
709 (define (sort-grade l sort-fn)
710   (let ((sorted (sort (map cons (iota (length l)) l)
711                       (lambda (a b) (sort-fn (cdr a) (cdr b))))))
712     (map car sorted))
713 )
714
715 ; Return ALIST sorted on the name in ascending order.
716
717 (define (alist-sort alist)
718   (sort alist
719         (lambda (a b)
720           (string<? (symbol->string (car a))
721                     (symbol->string (car b)))))
722 )
723
724 ; Return a boolean indicating if C is a leading id char.
725 ; '@' is treated as an id-char as it's used to delimit something that
726 ; sed will alter.
727
728 (define (leading-id-char? c)
729   (or (char-alphabetic? c)
730       (char=? c #\_)
731       (char=? c #\@))
732 )
733
734 ; Return a boolean indicating if C is an id char.
735 ; '@' is treated as an id-char as it's used to delimit something that
736 ; sed will alter.
737
738 (define (id-char? c)
739   (or (leading-id-char? c)
740       (char-numeric? c))
741 )
742
743 ; Return the length of the identifier that begins S.
744 ; Identifiers are any of letter, digit, _, @.
745 ; The first character must not be a digit.
746 ; ??? The convention is to use "-" between cgen symbols, not "_".
747 ; Try to handle "-" here as well.
748
749 (define (id-len s)
750   (if (leading-id-char? (string-ref s 0))
751       (let ((len (string-length s)))
752         (let loop ((n 0))
753           (if (and (< n len)
754                    (id-char? (string-ref s n)))
755               (loop (1+ n))
756               n)))
757       0)
758 )
759
760 ; Return number of characters in STRING until DELIMITER.
761 ; Returns #f if DELIMITER not present.
762 ; FIXME: Doesn't yet support \-prefixed delimiter (doesn't terminate scan).
763
764 (define (chars-until-delimiter string delimiter)
765   (let loop ((str string) (result 0))
766     (cond ((= (string-length str) 0)
767            #f)
768           ((char=? (string-ref str 0) delimiter)
769            result)
770           (else (loop (string-drop1 str) (1+ result)))))
771 )
772
773 ; Apply FN to each char of STR.
774
775 (define (map-over-string fn str)
776   (do ((tmp (string-copy (if (symbol? str) (symbol->string str) str)))
777        (i (- (string-length str) 1) (- i 1)))
778       ((< i 0) tmp)
779     (string-set! tmp i (fn (string-ref tmp i)))
780     )
781 )
782
783 ; Return a range.
784 ; It must be distinguishable from a list of numbers.
785
786 (define (minmax min max) (cons min max))
787
788 ; Move VALUE of LENGTH bits to position START in a word of SIZE bits.
789 ; LSB0? is non-#f if bit numbering goes LSB->MSB.
790 ; Otherwise it goes MSB->LSB.
791 ; START-LSB? is non-#f if START denotes the least significant bit.
792 ; Otherwise START denotes the most significant bit.
793 ; N is assumed to fit in the field.
794
795 (define (word-value start length size lsb0? start-lsb? value)
796   (if lsb0?
797       (if start-lsb?
798           (logsll value start)
799           (logsll value (+ (- start length) 1)))
800       (if start-lsb?
801           (logsll value (- size start 1))
802           (logsll value (- size (+ start length)))))
803 )
804
805 ; Return a bit mask of LENGTH bits in a word of SIZE bits starting at START.
806 ; LSB0? is non-#f if bit numbering goes LSB->MSB.
807 ; Otherwise it goes MSB->LSB.
808 ; START-LSB? is non-#f if START denotes the least significant bit.
809 ; Otherwise START denotes the most significant bit.
810
811 (define (word-mask start length size lsb0? start-lsb?)
812   (if lsb0?
813       (if start-lsb?
814           (logsll (mask length) start)
815           (logsll (mask length) (+ (- start length) 1)))
816       (if start-lsb?
817           (logsll (mask length) (- size start 1))
818           (logsll (mask length) (- size (+ start length)))))
819 )
820
821 ; Extract LENGTH bits at bit number START in a word of SIZE bits from VALUE.
822 ; LSB0? is non-#f if bit numbering goes LSB->MSB.
823 ; Otherwise it goes MSB->LSB.
824 ; START-LSB? is non-#f if START denotes the least significant bit.
825 ; Otherwise START denotes the most significant bit.
826 ;
827 ; ??? bit-extract takes a big-number argument but still uses logand
828 ; which doesn't so we don't use it
829
830 (define (word-extract start length size lsb0? start-lsb? value)
831   (if lsb0?
832       (if start-lsb?
833           (remainder (logslr value start) (integer-expt 2 length))
834           (remainder (logslr value (+ (- start length) 1)) (integer-expt 2 length)))
835       (if start-lsb?
836           (remainder (logslr value (- size start 1)) (integer-expt 2 length))
837           (remainder (logslr value (- size (+ start length))) (integer-expt 2 length))))
838 )
839
840 ; Return a bit mask of size SIZE beginning at the LSB.
841
842 (define (mask size)
843   (- (logsll 1 size) 1)
844 )
845
846 ; Split VAL into pieces of bit size LENGTHS.
847 ; e.g. (split-bits '(8 2) 997) -> (229 3)
848 ; There are as many elements in the result as there are in LENGTHS.
849 ; Note that this can result in a loss of information.
850
851 (define (split-bits lengths val)
852   (letrec ((split1
853             (lambda (lengths val result)
854               (if (null? lengths)
855                   result
856                   (split1 (cdr lengths)
857                           (quotient val (integer-expt 2 (car lengths)))
858                           (cons (remainder val (integer-expt 2 (car lengths)))
859                                 result))))))
860     (reverse! (split1 lengths val nil)))
861 )
862
863 ; Generalized version of split-bits.
864 ; e.g. (split-value '(10 10 10) 1234) -> (4 3 2 1) ; ??? -> (1 2 3 4) ?
865 ; (split-value '(10 10) 1234) -> (4 3)
866 ; There are as many elements in the result as there are in BASES.
867 ; Note that this can result in a loss of information.
868
869 (define (split-value bases val)
870   (letrec ((split1
871             (lambda (bases val result)
872               (if (null? bases)
873                   result
874                   (split1 (cdr bases)
875                           (quotient val (car bases))
876                           (cons (remainder val (car bases))
877                                 result))))))
878     (reverse! (split1 bases val nil)))
879 )
880
881 ; Convert bits to bytes.
882
883 (define (bits->bytes bits) (quotient (+ 7 bits) 8))
884
885 ; Convert bytes to bits.
886
887 (define (bytes->bits bytes) (* bytes 8))
888
889 ; Return a list of integers.
890 ; Usage:
891 ; (.iota count)            ; start=0, incr=1
892 ; (.iota count start)      ; incr=1
893 ; (.iota count start incr)
894
895 (define (iota count . start-incr)
896   (if (> (length start-incr) 2)
897       (error "iota: wrong number of arguments:" start-incr))
898   (if (< count 0)
899       (error "iota: count must be non-negative:" n))
900   (let ((start (if (pair? start-incr) (car start-incr) 0))
901         (incr (if (= (length start-incr) 2) (cadr start-incr) 1)))
902     (let loop ((i start) (count count) (result '()))
903       (if (= count 0)
904           (reverse! result)
905           (loop (+ i incr) (- count 1) (cons i result)))))
906 )
907
908 ; Return a list of the first N powers of 2.
909
910 (define (powers-of-2 n)
911   (cond ((= n 0) nil)
912         (else (cons (integer-expt 2 (1- n)) (powers-of-2 (1- n))))
913         )
914   ; Another way: (map (lambda (n) (ash 1 n)) (iota n))
915 )
916
917 ; I'm tired of writing (not (= foo bar)).
918
919 (define (!= a b) (not (= a b)))
920
921 ; Return #t if BIT-NUM (which is starting from LSB), is set in the binary
922 ; representation of non-negative integer N.
923
924 (define (bit-set? n bit-num)
925   ; ??? Quick hack to work around missing bignum support.
926   ;(= 1 (cg-logand (logslr n bit-num) 1))
927   (if (>= n #x20000000)
928       (if (>= bit-num 16)
929           (logbit? (- bit-num 16) (logslr n 16))
930           (logbit? bit-num (remainder n 65536)))
931       (logbit? bit-num n))
932 )
933
934 ; Return #t if each element of bools is #t.  Since Scheme considers any
935 ; non-#f value as #t we do too.
936 ; (all-true? '()) is #t since that is the identity element.
937
938 (define (all-true? bools)
939   (cond ((null? bools) #t)
940         ((car bools) (all-true? (cdr bools)))
941         (else #f))
942 )
943
944 ; Return #t if any element of BOOLS is #t.
945 ; If BOOLS is empty, return #f.
946
947 (define (any-true? bools)
948   (cond ((null? bools) #f)
949         ((car bools) #t)
950         (else (any-true? (cdr bools))))
951 )
952
953 ; Return count of true values.
954
955 (define (count-true flags)
956   (let loop ((result 0) (flags flags))
957     (if (null? flags)
958         result
959         (loop (+ result (if (car flags) 1 0))
960               (cdr flags))))
961 )
962
963 ; Return count of all ones in BITS.
964
965 (define (count-bits bits)
966   (let loop ((result 0) (bits bits))
967     (if (= bits 0)
968         result
969         (loop (+ result (remainder bits 2)) (quotient bits 2))))
970 )
971
972 ; Convert bits in N #f/#t.
973 ; LENGTH is the length of N in bits.
974
975 (define (bits->bools n length)
976   (do ((result (make-list length #f))
977        (i 0 (+ i 1)))
978       ((= i length) (reverse! result))
979     (list-set! result i (if (bit-set? n i) #t #f))
980     )
981 )
982
983 ; Print a C integer.
984
985 (define (gen-integer val)
986   (cond ((and (<= #x-80000000 val) (> #x80000000 val))
987          (number->string val))
988         ((and (<= #x80000000 val) (>= #xffffffff val))
989          ; ??? GCC complains if not affixed with "U" but that's not k&r.
990          ;(string-append (number->string val) "U"))
991          (string-append "0x" (number->string val 16)))
992         (else (error "Number too large for gen-integer:" val)))
993 )
994
995 ; Return higher/lower part of double word integer.
996
997 (define (high-part val)
998   (logslr val 32)
999 )
1000 (define (low-part val)
1001   (remainder val #x100000000)
1002 )
1003
1004 ; Logical operations.
1005
1006 (define (logslr val shift) (ash val (- shift)))
1007 (define logsll ash) ; (logsll val shift) (ash val shift))
1008
1009 ; logand, logior, logxor defined by guile so we don't need to
1010 ; (define (logand a b) ...)
1011 ; (define (logxor a b) ...)
1012 ; (define (logior a b) ...)
1013 ;
1014 ; On the other hand they didn't support bignums, so the cgen-binary
1015 ; defines cg-log* that does.  These are just a quick hack that only
1016 ; handle what currently needs handling.
1017
1018 (define (cg-logand a b)
1019   (if (or (>= a #x20000000)
1020           (>= b #x20000000))
1021       (+ (logsll (logand (logslr a 16) (logslr b 16)) 16)
1022          (logand (remainder a 65536) (remainder b 65536)))
1023       (logand a b))
1024 )
1025
1026 (define (cg-logxor a b)
1027   (if (or (>= a #x20000000)
1028           (>= b #x20000000))
1029       (+ (logsll (logxor (logslr a 16) (logslr b 16)) 16)
1030          (logxor (remainder a 65536) (remainder b 65536)))
1031       (logxor a b))
1032 )
1033
1034 ; Return list of bit values for the 1's in X.
1035
1036 (define (bit-vals x)
1037   (let loop ((result nil) (mask 65536))
1038     (cond ((= mask 0) result)
1039           ((> (logand x mask) 0) (loop (cons mask result) (logslr mask 1)))
1040           (else (loop result (logslr mask 1)))))
1041 )
1042
1043 ; Return bit representation of N in LEN bits.
1044 ; e.g. (bit-rep 6 3) -> (1 1 0)
1045
1046 (define (bit-rep n len)
1047   (cond ((= len 0) nil)
1048         ((> (logand n (logsll 1 (- len 1))) 0)
1049          (cons 1 (bit-rep n (- len 1))))
1050         (else (cons 0 (bit-rep n (- len 1))))))
1051
1052 ; Return list of all bit values from 0 to N.
1053 ; e.g. (bit-patterns 3) -> ((0 0 0) (0 0 1) (0 1 0) ... (1 1 1))
1054
1055 (define (bit-patterns len)
1056   (map (lambda (x) (bit-rep x len)) (iota (logsll 1 len)))
1057 )
1058
1059 ; Compute the list of all indices from bits missing in MASK.
1060 ; e.g. (missing-bit-indices #xff00 #xffff) -> (0 1 2 3 ... 255)
1061
1062 (define (missing-bit-indices mask full-mask)
1063   (let* ((bitvals (bit-vals (logxor mask full-mask)))
1064          (selectors (bit-patterns (length bitvals)))
1065          (map-star (lambda (sel) (map * sel bitvals)))
1066          (compute-indices (lambda (sel) (apply + (map-star sel)))))
1067     (map compute-indices selectors))
1068 )
1069
1070 ; Return #t if n is a non-negative integer.
1071
1072 (define (non-negative-integer? n)
1073   (and (integer? n)
1074        (>= n 0))
1075 )
1076
1077 ; Convert a list of numbers to a string, separated by SEP.
1078 ; The result is prefixed by SEP too.
1079
1080 (define (numbers->string nums sep)
1081   (string-map (lambda (elm) (string-append sep (number->string elm))) nums)
1082 )
1083
1084 ; Convert a number to a hex string.
1085
1086 (define (number->hex num)
1087   (number->string num 16)
1088 )
1089
1090 ; Given a list of numbers NUMS, generate text to pass them as arguments to a
1091 ; C function.  We assume they're not the first argument and thus have a
1092 ; leading comma.
1093
1094 (define (gen-int-args nums)
1095   (numbers->string nums ", ")
1096 )
1097
1098 ; Given a C expression or a list of C expressions, return a comma separated
1099 ; list of them.
1100 ; In the case of more than 0 elements the leading ", " is present so that
1101 ; there is no edge case in the case of 0 elements when the caller is appending
1102 ; the result to an initial set of arguments (the number of commas equals the
1103 ; number of elements).  The caller is responsible for dropping the leading
1104 ; ", " if necessary.  Note that `string-drop' can handle the case where more
1105 ; characters are dropped than are present.
1106
1107 (define (gen-c-args exprs)
1108   (cond ((null? exprs) "")
1109         ((pair? exprs) (string-map (lambda (elm) (string-append ", " elm))
1110                                    exprs))
1111         ((equal? exprs "") "")
1112         (else (string-append ", " exprs)))
1113 )
1114
1115 ; Return a list of N macro argument names.
1116
1117 (define (macro-args n)
1118   (map (lambda (i) (string-append "a" (number->string i)))
1119        (map 1+ (iota n)))
1120 )
1121
1122 ; Return C code for N macro argument names.
1123 ; (gen-macro-args 4) -> ", a1, a2, a3, a4"
1124
1125 (define (gen-macro-args n)
1126   (gen-c-args (macro-args n))
1127 )
1128
1129 ; Return a string to reference an array.
1130 ; INDICES is either a (possibly empty) list of indices or a single index.
1131 ; The values can either be numbers or strings (/symbols).
1132
1133 (define (gen-array-ref indices)
1134   (let ((gen-index (lambda (idx)
1135                      (string-append "["
1136                                     (cond ((number? idx) (number->string idx))
1137                                           (else idx))
1138                                     "]"))))
1139     (cond ((null? indices) "")
1140           ((pair? indices) ; list of indices?
1141            (string-map gen-index indices))
1142           (else (gen-index indices))))
1143 )
1144
1145 ; Return list element N or #f if list L is too short.
1146
1147 (define (list-maybe-ref l n)
1148   (if (> (length l) n)
1149       (list-ref l n)
1150       #f)
1151 )
1152
1153 ; Return list of index numbers of elements in list L that satisfy PRED.
1154 ; I is added to each index, it's usually 0.
1155
1156 (define (find-index i pred l)
1157   (define (find1 i pred l result)
1158     (cond ((null? l) result)
1159           ((pred (car l)) (find1 (+ 1 i) pred (cdr l) (cons i result)))
1160           (else (find1 (+ 1 i) pred (cdr l) result))))
1161   (reverse! (find1 i pred l nil))
1162 )
1163
1164 ; Return index number of first element in list L that satisfy PRED.
1165 ; Returns #f if not present.
1166 ; I is added to the result, it's usually 0.
1167
1168 (define (find-first-index i pred l)
1169   (cond ((null? l) #f)
1170         ((pred (car l)) i)
1171         (else (find-first-index (+ 1 i) pred (cdr l))))
1172 )
1173
1174 ; Return list of elements of L that satisfy PRED.
1175
1176 (define (find pred l)
1177   (define (find1 pred l result)
1178     (cond ((null? l) result)
1179           ((pred (car l)) (find1 pred (cdr l) (cons (car l) result)))
1180           (else (find1 pred (cdr l) result))))
1181   (reverse! (find1 pred l nil))
1182 )
1183
1184 ; Return first element of L that satisfies PRED or #f if there is none.
1185
1186 (define (find-first pred l)
1187   (cond ((null? l) #f)
1188         ((pred (car l)) (car l))
1189         (else (find-first pred (cdr l))))
1190 )
1191
1192 ; Return list of FN applied to elements of L that satisfy PRED.
1193
1194 (define (find-apply fn pred l)
1195   (cond ((null? l) nil)
1196         ((pred (car l)) (cons (fn (car l)) (find-apply fn pred (cdr l))))
1197         (else (find-apply fn pred (cdr l))))
1198 )
1199
1200 ; Given a list L, look up element ELM and return its index.
1201 ; If not found, return #f.
1202 ; I is added to the result.
1203 ; (Yes, in one sense I is present to simplify the implementation.  Sue me.)
1204
1205 (define (eqv-lookup-index elm l i)
1206   (cond ((null? l) #f)
1207         ((eqv? elm (car l)) i)
1208         (else (eqv-lookup-index elm (cdr l) (1+ i))))
1209 )
1210
1211 ; Given an associative list L, look up entry for symbol S and return its index.
1212 ; If not found, return #f.
1213 ; Eg: (lookup 'element2 '((element1 1) (element2 2)))
1214 ; I is added to the result.
1215 ; (Yes, in one sense I is present to simplify the implementation.  Sue me.)
1216 ; NOTE: Uses eq? for comparisons.
1217
1218 (define (assq-lookup-index s l i)
1219   (cond ((null? l) #f)
1220         ((eqv? s (caar l)) i)
1221         (else (assq-lookup-index s (cdr l) (1+ i))))
1222 )
1223
1224 ; Return the index of element ELM in list L or #f if not found.
1225 ; If found, I is added to the result.
1226 ; (Yes, in one sense I is present to simplify the implementation.  Sue me.)
1227 ; NOTE: Uses equal? for comparisons.
1228
1229 (define (element-lookup-index elm l i)
1230   (cond ((null? l) #f)
1231         ((equal? elm (car l)) i)
1232         (else (element-lookup-index elm (cdr l) (1+ i))))
1233 )
1234
1235 ; Return #t if ELM is in ELM-LIST.
1236 ; NOTE: Uses equal? for comparisons (via `member').
1237
1238 (define (element? elm elm-list)
1239   (->bool (member elm elm-list))
1240 )
1241
1242 ; Return the set of all possible combinations of elements in list L
1243 ; according to the following rules:
1244 ; - each element of L is either an atom (non-list) or a list
1245 ; - each list element is (recursively) interpreted as a set of choices
1246 ; - the result is a list of all possible combinations of elements
1247 ;
1248 ; Example: (list-expand '(a b (1 2 (3 4)) c (5 6)))
1249 ; --> ((a b 1 c d 5)
1250 ;      (a b 1 c d 6)
1251 ;      (a b 2 c d 5)
1252 ;      (a b 2 c d 6)
1253 ;      (a b 3 c d 5)
1254 ;      (a b 3 c d 6)
1255 ;      (a b 4 c d 5)
1256 ;      (a b 4 c d 6))
1257
1258 (define (list-expand l)
1259   #f ; ??? wip
1260 )
1261
1262 ; Given X, a number or symbol, reduce it to a constant if possible.
1263 ; Numbers always reduce to themselves.
1264 ; Symbols are reduced to a number if they're defined as such,
1265 ; or to an enum constant if one exists; otherwise X is returned unchanged.
1266 ; Requires: symbol-bound? enum-lookup-val
1267
1268 (define (reduce x)
1269   (if (number? x)
1270       x
1271       ; A symbol bound to a number?
1272       (if (and (symbol? x) (symbol-bound? #f x) (number? (eval1 x)))
1273           (eval1 x)
1274           ; An enum value that has a known numeric value?
1275           (let ((e (enum-lookup-val x)))
1276             (if (number? (car e))
1277                 (car e)
1278                 ; Otherwise return X unchanged.
1279                 x))))
1280 )
1281
1282 ; If OBJ has a dump method call it, otherwise return OBJ untouched.
1283
1284 (define (dump obj)
1285   (if (method-present? obj 'dump)
1286       (send obj 'dump)
1287       obj)
1288 )
1289 \f
1290 ; Copyright messages.
1291
1292 ; Pair of header,trailer parts of copyright.
1293
1294 (define copyright-fsf
1295   (cons "\
1296 THIS FILE IS MACHINE GENERATED WITH CGEN.
1297
1298 Copyright 1996-2009 Free Software Foundation, Inc.
1299 "
1300         "\
1301    This file is free software; you can redistribute it and/or modify
1302    it under the terms of the GNU General Public License as published by
1303    the Free Software Foundation; either version 3, or (at your option)
1304    any later version.
1305
1306    It is distributed in the hope that it will be useful, but WITHOUT
1307    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
1308    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
1309    License for more details.
1310
1311    You should have received a copy of the GNU General Public License along
1312    with this program; if not, write to the Free Software Foundation, Inc.,
1313    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
1314 "
1315 ))
1316
1317 ; Pair of header,trailer parts of copyright.
1318
1319 (define copyright-red-hat
1320   (cons "\
1321 THIS FILE IS MACHINE GENERATED WITH CGEN.
1322
1323 Copyright (C) 2000-2009 Red Hat, Inc.
1324 "
1325         "\
1326 "))
1327
1328 ; Set this to one of copyright-fsf, copyright-red-hat.
1329
1330 (define CURRENT-COPYRIGHT copyright-fsf)
1331
1332 ; Packages.
1333
1334 (define package-gnu-binutils-gdb "\
1335 This file is part of the GNU Binutils and/or GDB, the GNU debugger.
1336 ")
1337
1338 (define package-gnu-simulators "\
1339 This file is part of the GNU simulators.
1340 ")
1341
1342 (define package-red-hat-simulators "\
1343 This file is part of the Red Hat simulators.
1344 ")
1345
1346 (define package-cgen "\
1347 This file is part of CGEN.
1348 ")
1349
1350 ; Return COPYRIGHT, with FILE-DESC as the first line
1351 ; and PACKAGE as the name of the package which the file belongs in.
1352 ; COPYRIGHT is a pair of (header . trailer).
1353
1354 (define (gen-c-copyright file-desc copyright package)
1355   (string-append "/* " file-desc "\n\n"
1356                  (car copyright)
1357                  "\n" package "\n"
1358                  (cdr copyright)
1359                  "\n*/\n\n")
1360 )
1361 \f
1362 ; File operations.
1363
1364 ; Delete FILE, handling the case where it doesn't exist.
1365
1366 (define (delete-file-noerr file)
1367   ; This could also use file-exists?, but it's nice to have a few examples
1368   ; of how to use `catch' lying around.
1369   (catch 'system-error (lambda () (delete-file file))
1370          (lambda args #f))
1371 )
1372
1373 ; Create FILE, point current-output-port to it, and call WRITE-FN.
1374 ; FILE is always overwritten.
1375 ; GEN-FN either writes output to stdout or returns the text to write,
1376 ; the last thing we do is write the text returned by WRITE-FN to FILE.
1377
1378 (define (file-write file write-fn)
1379   (delete-file-noerr file)
1380   (let ((left-over-text (with-output-to-file file write-fn)))
1381     (let ((port (open-file file "a")))
1382       (display left-over-text port)
1383       (close-port port))
1384     #t)
1385 )
1386
1387 ; Return the size in bytes of FILE.
1388
1389 (define (file-size file)
1390   (let ((stat (%stat file)))
1391     (if stat
1392         (vector-ref (%stat file) 7)
1393         -1))
1394 )
1395 \f
1396 ; Time operations.
1397
1398 ; Return the current time.
1399 ; The result is a black box understood only by time-elapsed.
1400
1401 (define (time-current) (gettimeofday))
1402
1403 ; Return the elapsed time in milliseconds since START.
1404
1405 (define (time-elapsed start)
1406   (let ((now (gettimeofday)))
1407     (+ (* (- (car now) (car start)) 1000)
1408        (quotient (- (cdr now) (cdr start)) 1000)))
1409 )
1410
1411 ; Run PROC and return the number of milliseconds it took to execute it N times.
1412
1413 (define (time-proc n proc)
1414   (let ((now (time-current)))
1415     (do ((i 0 (+ i 1))) ((= i n) (time-elapsed now))
1416       (proc)))
1417 )
1418 \f
1419 ;; Debugging repls.
1420
1421 ; Record of arguments passed to debug-repl, so they can be accessed in
1422 ; the repl loop.
1423
1424 (define debug-env #f)
1425
1426 ; Return list of recorded variables for debugging.
1427
1428 (define (debug-var-names) (map car debug-env))
1429
1430 ; Return value of recorded var NAME.
1431
1432 (define (debug-var name) (assq-ref debug-env name))
1433
1434 ; A handle on /dev/tty, so we can be sure we're talking with the user.
1435 ; We open this the first time we actually need it.
1436
1437 (define debug-tty #f)
1438
1439 ; Return the port we should use for interacting with the user,
1440 ; opening it if necessary.
1441
1442 (define (debug-tty-port)
1443   (if (not debug-tty)
1444       (set! debug-tty (open-file "/dev/tty" "r+")))
1445   debug-tty)
1446
1447 ; Enter a repl loop for debugging purposes.
1448 ; Use (quit) to exit cgen completely.
1449 ; Use (debug-quit) or (quit 0) to exit the debugging session and
1450 ; resume argument processing.
1451 ;
1452 ; ENV-ALIST can be anything, but it is intended to be an alist of values
1453 ; the caller will want to be able to access in the repl loop.
1454 ; It is stored in global `debug-env'.
1455
1456 (define (debug-repl env-alist)
1457   (with-input-and-output-to
1458    (debug-tty-port)
1459    (lambda ()
1460      (set! debug-env env-alist)
1461      (let loop ()
1462        (let ((rc (top-repl)))
1463          (if (null? rc)
1464              (quit 1))                  ; indicate error to `make'
1465          (if (not (equal? rc '(0)))
1466              (loop))))))
1467 )
1468
1469 ; Utility for debug-repl.
1470
1471 (define (debug-quit)
1472   ; Keep around for later debugging.
1473   ;(set! debug-env #f)
1474
1475   (quit 0)
1476 )
1477
1478 ; Macro to simplify calling debug-repl.
1479 ; Usage: (debug-repl-env var-name1 var-name2 ...)
1480 ;
1481 ; This is for debugging cgen itself, and is inserted into code at the point
1482 ; where one wants to start a repl.
1483
1484 (defmacro debug-repl-env var-names
1485   (let ((env (map (lambda (var-name)
1486                     (list 'cons (list 'quote var-name) var-name))
1487                   var-names)))
1488     (list 'debug-repl (cons 'list env)))
1489 )