1 /*
2  * top level loop, aux functions for the debugger, stepper for CLISP
3  * Bruno Haible 1990-2005, 2016-2017
4  * ILISP friendliness: Marcus Daniels 8.4.1994
5  * Sam Steingold 2001-2011
6  * German comments translated into English: Stefan Kain 2004-08-30
7  */
8 
9 #include "lispbibl.c"
10 
11 
12 /* -----------------------------------------------------------------------
13  Top-Level-Loop
14 
15  SYS::READ-FORM realizes the following features of the top-level REP loop
16    and of the debug REP loop:
17 
18    - The prompt. When the input stream is interactive, a prompt is printed
19      that reminds the user that the system is expecting a Lisp form.
20      "> " or "1. Break> " or something like this.
21      When the input stream is not interactive, such as in "clisp < in.lisp",
22      no prompt is emitted, because these prompt would accumulate on standard
23      output, without being useful.
24      We use the criterion "interactive", not the criterion "output device =
25      input device", because in situations like "clisp | tee logfile", which
26      are interactive but with different devices for input and output, the
27      prompt is desirable.
28 
29    - The continuation prompt [not yet implemented]. When the input stream is
30      interactive a short prompt is printed after each newline that reminds
31      the user if the reader is reading a string "..." or symbol |...| which
32      is not yet complete.
33 
34    - The key/command bindings. The user can enter some special words like
35      "help", ":q", "continue", "abort", which are recognized as commands.
36      They can be given as argument or via SYS::*KEY-BINDINGS*. (The name of
37      this variable comes from the Atari ST time, when most of the commands
38      were accessible through function keys F1..F10.) Example:
39 
40      [1]> (/ 0)
41 
42      *** - division by zero
43      The following restarts are available:
44      ABORT          :R1      ABORT
45 
46      Break 1 [2]> abort
47 
48      [3]>
49 
50    - Support for paste: When a user pastes a couple of forms into the command
51      line, all are executed.
52 
53      [1]> (setq x 3) (setq y 4) (setq z (sqrt (+ (* x x) (* y y))))
54      3
55      [2]>
56      4
57      [3]>
58      5
59      [4]>
60 
61    - Likewise for multiline paste:
62 
63      [1]> (setq x 3)
64           (setq y 4)
65           (setq z (sqrt (+ (* x x) (* y y))))
66      3
67      [2]>
68      4
69      [3]>
70      5
71      [4]>
72 
73    - Separation of form input and data input.
74 
75      Form input is not mistakenly considered as data. Example:
76 
77      [1]> (read-line) (cons 'a 'b)
78      data
79      "data" ;
80      NIL
81      [2]>
82      (A . B)
83      [3]>
84 
85      *not*
86 
87      [1]> (read-line) (cons 'a 'b)
88      "(cons 'a 'b)" ;
89      NIL
90      [2]>
91 
92      Data input is not mistakenly considered as forms. Example:
93 
94      [1]> (read-char)
95      abcdef
96      #\a
97      [2]>
98 
99      *not*
100 
101      [1]> (read-char)
102      abcdef
103      #\a
104      [2]>
105      *** - EVAL: variable BCDEF has no value
106 
107 
108  (SYS::READ-FORM ostream istream prompt [commandlist])
109  read one form (interactively) from the input stream.
110  instead of the form, we also recognize special commands from commandlist
111  (a fresh alist) or SYS::*KEY-BINDINGS*
112  > STACK_1: prompt, a string
113  > STACK_0: commandlist (fresh aliste) or #<UNBOUND>
114  < STACK_1: Output-Stream *standard-output*
115  < STACK_0: Input-Stream *standard-input*
116  < mv_space/mv_count: value = form, NIL or (on EOF) T, T
117  can trigger GC */
read_form(void)118 local maygc Values read_form(void)
119 { /*
120  (defun read-form (ostream istream prompt &optional (command-list nil))
121    (loop
122      (let ((raw (terminal-raw istream nil)))
123        (when (interactive-stream-p istream)
124          (fresh-line ostream)
125          (write-string prompt ostream)
126          (force-output ostream))
127        (let* ((eof-value "EOF")
128               (form (let ((*read-suppress* nil)
129                           (*key-bindings* (nreconc command-list
130                                                    *key-bindings*)))
131                       (read istream nil eof-value nil))))
132          (terminal-raw istream raw)
133          (if (eql form eof-value)
134            (progn (clear-input istream) (setq istream *debug-io*))
135            (progn (clear-input-upto-newline istream)
136                   (return (values form nil))))))))   */
137  #if STACKCHECKR
138   var gcv_object_t* STACKbefore = STACK; /* retain STACK for later */
139  #endif
140   pushSTACK(STACK_1); pushSTACK(STACK_1);
141   STACK_3 = var_stream(S(standard_output),strmflags_wr_ch_B); /* ostream := *STANDARD-OUTPUT* */
142   STACK_2 = var_stream(S(standard_input),strmflags_rd_ch_B); /* istream := *STANDARD-INPUT* */
143   /* stack layout: ostream, istream, prompt, command-list. */
144   pushSTACK(STACK_2);
145   pushSTACK(STACK_3); pushSTACK(NIL); funcall(L(terminal_raw),2);
146   pushSTACK(value1);
147   /* stack layout: ostream, istream, prompt, command-list, inputstream, raw. */
148   if (listen_char(STACK_4) == LISTEN_EOF
149       && !boundp(Symbol_value(S(terminal_read_stream))))
150     goto eof;
151   /* already have characters available (and not in ilisp_mode) -> no prompt */
152   if (ilisp_mode || interactive_stream_p(STACK_4)) {
153     /* interactive input-stream -> prompt output: */
154    #if 0
155     fresh_line(&STACK_5); /* (FRESH-LINE ostream) */
156    #else
157     /* the same, but avoiding infinite recursion
158      (let ((*recurse-count-standard-output*
159             (1+ *recurse-count-standard-output*)))
160        (when (> *recurse-count-standard-output* 3)
161          (setq *recurse-count-standard-output* 0)
162          (makunbound (quote *standard-output*))
163          (let ((*recurse-count-debug-io* (1+ *recurse-count-debug-io*)))
164            (when (> *recurse-count-debug-io* 3)
165              (setq *recurse-count-debug-io* 0)
166              (makunbound (quote *debug-io*))
167              (symbol-stream (quote *debug-io*) :io))
168            (symbol-stream (quote *standard-output*) :output)))
169        (fresh-line *standard-output*)) */
170     /* (incf sys::*recurse-count-standard-output*) */
171     dynamic_bind(S(recurse_count_standard_output),
172                  fixnum_inc(Symbol_value(S(recurse_count_standard_output)),1));
173     if (!posfixnump(Symbol_value(S(recurse_count_standard_output))))
174       /* should be fixnum >=0; otherwise emergency correction */
175       Symbol_value(S(recurse_count_standard_output)) = Fixnum_0;
176     if (posfixnum_to_V(Symbol_value(S(recurse_count_standard_output))) > 3) {
177       /* too many nested i/o errors. */
178       Symbol_value(S(recurse_count_standard_output)) = Fixnum_0;
179       Symbol_value(S(standard_output)) = unbound;
180        /* (incf sys::*recurse-count-debug-io*): */
181       dynamic_bind(S(recurse_count_debug_io),
182                    fixnum_inc(Symbol_value(S(recurse_count_debug_io)),1));
183       if (!posfixnump(Symbol_value(S(recurse_count_debug_io))))
184         /* should be fixnum >=0; otherwise emergency correction */
185         Symbol_value(S(recurse_count_debug_io)) = Fixnum_0;
186       if (posfixnum_to_V(Symbol_value(S(recurse_count_debug_io))) > 3) {
187         /* too many nested i/o errors. */
188         Symbol_value(S(recurse_count_debug_io)) = Fixnum_0;
189         Symbol_value(S(debug_io)) = unbound;
190         var_stream(S(debug_io),strmflags_rd_ch_B|strmflags_wr_ch_B);
191       }
192       STACK_(5+3+3) = var_stream(S(standard_output),strmflags_wr_ch_B); /* ostream := *STANDARD-OUTPUT* */
193       dynamic_unbind(S(recurse_count_debug_io));
194     }
195     fresh_line(&STACK_(5+3)); /* (FRESH-LINE ostream) */
196     dynamic_unbind(S(recurse_count_standard_output));
197    #endif
198     write_string(&STACK_5,STACK_3); /* (WRITE-STRING prompt ostream) */
199     force_output(STACK_5);
200   } /* Prompt OK */
201   {
202     var gcv_object_t* inputstream_ = &STACK_1;
203   #if 0
204     /* That proves nevertheless awkward: If one presses CTRL-C during input,
205        then one has some commands then in the BREAK loop doubly in the list */
206     {
207       var object list = Symbol_value(S(key_bindings)); /* old Key-Bindings */
208       if (boundp(STACK_2)) /* command-list supplied? */
209         list = nreconc(STACK_2,list); /* add in front */
210       dynamic_bind(S(key_bindings),list); /* bind SYS::*KEY-BINDINGS* */
211     }
212    #else
213     {
214       var object list = (!boundp(STACK_2) ? NIL : (object)STACK_2);
215       dynamic_bind(S(key_bindings),list); /* bind SYS::*KEY-BINDINGS* */
216     }
217    #endif
218    #if !defined(TERMINAL_USES_KEYBOARD) /*  Atari - function keys */
219     var bool terminal_read_stream_bound = false;
220     if (interactive_stream_p(*(inputstream_ STACKop 3)) /* only for interactive input streams */
221         && !boundp(Symbol_value(S(terminal_read_stream)))) {
222       /* look for commands, not forms:
223        (multiple-value-bind (line flag) (read-line istream)
224          (let ((h (assoc line *key-bindings* :test (function string-equal))))
225            (when h (funcall (cdr h)) (return t)))
226          (setq istream
227                (make-concatenated-stream
228                 (make-string-input-stream
229                  (if flag line
230                      (concatenate (quote string) line (string #\Newline))))
231                 istream))) */
232       do {
233         /* this loop is for win32 and its C-z RET abomination: after
234            C-z (EOF) is processed, there is an empty line in the stream */
235         pushSTACK(*inputstream_); pushSTACK(NIL); pushSTACK(NIL);
236         funcall(L(read_line),3); /* (READ-LINE istream nil nil) */
237         if (nullp(value1)) { /* EOF at line start? */
238           dynamic_unbind(S(key_bindings));
239           goto eof;
240         }
241       } while (Sstring_length(value1) == 0);
242       var object line = value1; /* non-trivial line */
243       /* NB: READ-LINE returns a SIMPLE-STRING in CLISP, so line is simple */
244       { /* search for line in *KEY-BINDINGS*: */
245         var object alist = Symbol_value(S(key_bindings));
246         var uintL input_len = Sstring_length(line);
247         for (;consp(alist);alist = Cdr(alist))
248           if (mconsp(Car(alist)) && simple_string_p(Car(Car(alist)))) {
249             var object key = Car(Car(alist));
250             sstring_un_realloc(key);
251             var uintL len = Sstring_length(key);
252             /* check whether the line starts with the key and a whitespace */
253             if ((len <= input_len) && string_eqcomp_ci(line,0,key,0,len)) {
254               if (len == input_len) goto found;
255               /* now len < input_len */
256               { var chart ch = schar(line,len);
257                 if (cint_white_p(as_cint(ch))) goto found;
258               }
259               if (false) { found:
260                 pushSTACK(Cdr(Car(alist))); /* save the function */
261                 pushSTACK(subsstring(line,len,input_len));
262                 funcall(STACK_1,1); /* call the appropriate function */
263                 skipSTACK(1);       /* drop the function */
264                 dynamic_unbind(S(key_bindings));
265                 goto eof;
266               }
267             }
268           }
269       }
270       /* create string-input-stream for this line: */
271       if (nullp(value2)) {
272         pushSTACK(line); pushSTACK(O(newline_string));
273         line = string_concat(2); /* maybe need another Newline */
274       }
275       pushSTACK(line); funcall(L(make_string_input_stream),1);
276       /* make concatenated-stream: */
277       pushSTACK(value1); pushSTACK(*inputstream_);
278       funcall(L(make_concatenated_stream),2);
279       dynamic_bind(S(terminal_read_stream),value1);
280       terminal_read_stream_bound = true;
281       *inputstream_ = Symbol_value(S(terminal_read_stream));
282     } else if (streamp(Symbol_value(S(terminal_read_stream)))) {
283       var object stream = Symbol_value(S(terminal_read_stream));
284       Symbol_value(S(terminal_read_stream)) = unbound;
285       dynamic_bind(S(terminal_read_stream),stream);
286       terminal_read_stream_bound = true;
287       *inputstream_ = Symbol_value(S(terminal_read_stream));
288     }
289    #endif  /* !defined(TERMINAL_USES_KEYBOARD) */
290     dynamic_bind(S(read_suppress),NIL); /* *READ-SUPPRESS* = NIL */
291     /* read object (recursive-p=NIL, whitespace-p=NIL): */
292     var object obj = stream_read(inputstream_,NIL,NIL);
293     dynamic_unbind(S(read_suppress));
294    #if !defined(TERMINAL_USES_KEYBOARD)
295     if (terminal_read_stream_bound) {
296       var object old_trs = Symbol_value(S(terminal_read_stream));
297       dynamic_unbind(S(terminal_read_stream));
298       if (streamp(old_trs)) {
299         /* maybe need to process something from the first line? */
300         var object strm_list = TheStream(old_trs)->strm_concat_list;
301         pushSTACK(obj); /* save before PEEK-CHAR */
302         pushSTACK(old_trs); /* save before PEEK-CHAR */
303         Symbol_value(S(terminal_read_stream)) =
304           (consp(strm_list) && !nullp(Cdr(strm_list))
305            /* some input on the first line was not processed ? */
306            && (pushSTACK(T), pushSTACK(Car(strm_list)),
307                pushSTACK(NIL), pushSTACK(eof_value),
308                funcall(L(peek_char),4), !eq(value1,eof_value)))
309           ? STACK_0 : (gcv_object_t)unbound;
310         skipSTACK(1); /* drop old_trs */
311         obj = popSTACK();
312       }
313     }
314    #endif
315     dynamic_unbind(S(key_bindings));
316     if (!eq(obj,eof_value)) { /* EOF test (after whitespace) */
317       pushSTACK(obj);
318       pushSTACK(STACK_(4+1)); pushSTACK(STACK_(0+1+1)); funcall(L(terminal_raw),2);
319       /* If not at the beginning of a line, delete input till EOL: */
320       if (interactive_stream_p(STACK_(4+1))
321           && !eq(stream_get_lastchar(STACK_(4+1)),ascii_char(NL))) {
322         while (LISTEN_AVAIL == listen_char(STACK_(4+1))) {
323           var object ch = peek_char(&STACK_(4+1));
324           if (eq(ch,eof_value))
325             break;
326           read_char(&STACK_(4+1));
327           if (eq(ch,ascii_char(NL)))
328             break;
329         }
330       }
331       VALUES2(popSTACK(), NIL); /* (values obj NIL) */
332       skipSTACK(4);
333      #if STACKCHECKR
334       if (STACK != STACKbefore) /* verify if Stack is cleaned up */
335         abort(); /* if not --> go to Debugger */
336      #endif
337       return;
338     }
339   }
340  eof: /* reached EOF */
341   pushSTACK(STACK_4); pushSTACK(STACK_(0+1)); funcall(L(terminal_raw),2);
342   /* call (CLEAR-INPUT istream) to eat EOF from an interactive stream,
343      because a continuable program could misunderstand the EOF: */
344   clear_input(STACK_4);
345   VALUES2(T,T); /* (values T T) */
346   skipSTACK(4);
347  #if STACKCHECKR
348   if (STACK != STACKbefore) /* verify that STACK is cleaned up */
349     abort(); /* if not --> go to Debugger */
350  #endif
351 }
352 
353 /* (SYS::READ-FORM prompt [commandlist])
354  reads a form (interactively) from *standard-input*.
355  prompt must be a String.
356  A special key from commandlist (a fresh
357  Alist) or SYS::*KEY-BINDINGS* can be entered instead of a form.
358  Values: form, NIL or (on EOF) T, T */
359 LISPFUN(read_form,seclass_default,1,1,norest,nokey,0,NIL)
360 { read_form(); skipSTACK(2); }
361 
362 /* (SYS::READ-EVAL-PRINT prompt [commandlist])
363  reads a form, evaluates it and prints the values.
364  prompt must be a String.
365  A special key from commandlist (a fresh
366  Alist) or SYS::*KEY-BINDINGS* can be entered instead of a form.
367  Values: NIL or (on special key or EOF) T */
368 LISPFUN(read_eval_print,seclass_default,1,1,norest,nokey,0,NIL)
369 /* (defun read-eval-print (prompt &optional (command-list nil))
370    (multiple-value-bind (form flag)
371        (read-form *standard-output* *standard-input* prompt command-list)
372      (if flag
373        form ; return T
374        (progn
375          (setq +++ ++ ++ + + - - form)
376          (let ((vals (multiple-value-list (eval-env form [currentEnvironment]))))
377            (setq /// // // / / vals)
378            (setq *** ** ** * * (first vals))
379            ; primitive:
380          #|(do ((ostream *standard-output*)
381                 (L vals (cdr L)))
382                ((atom L))
383              (write (car L) ostream)
384              (when (consp (cdr L))
385                (write-string " ;" ostream)
386                (terpri ostream)))
387          |#; avoid unnecessary empty line between input and output:
388            (let ((ostream *standard-output*))
389              (fresh-line ostream)
390              (when (consp vals)
391                (write (car vals) ostream)
392                (do ((L (cdr vals) (cdr L)))
393                    ((atom L))
394                  (write-string " ;" ostream)
395                  (terpri ostream)
396                  (write (car L) ostream)))
397              (elastic-newline ostream)))
398          nil)))) */
399 {
400   read_form();                /* read form */
401   /* stack layout: ostream, istream. */
402   if (!nullp(value2)) {               /* flag ? */
403     mv_count=1; skipSTACK(2); return; /* return T as value */
404   }
405   Symbol_value(S(plus3)) = Symbol_value(S(plus2)); /* (SETQ +++ ++) */
406   Symbol_value(S(plus2)) = Symbol_value(S(plus));  /* (SETQ ++ +) */
407   Symbol_value(S(plus)) = Symbol_value(S(minus));  /* (SETQ + -) */
408   Symbol_value(S(minus)) = value1;                 /* (SETQ - form) */
409   eval(value1);           /* evaluate form (in current environment) */
410   pushSTACK(value1);          /* save a value */
411   mv_to_list();               /* pack values into list */
412   /* stack layout: ..., val1, vals. */
413   Symbol_value(S(slash3)) = Symbol_value(S(slash2)); /* (SETQ /// //) */
414   Symbol_value(S(slash2)) = Symbol_value(S(slash));  /* (SETQ // /) */
415   Symbol_value(S(slash)) = STACK_0;                  /* (SETQ / vals) */
416   Symbol_value(S(star3)) = Symbol_value(S(star2));   /* (SETQ *** **) */
417   Symbol_value(S(star2)) = Symbol_value(S(star));    /* (SETQ ** *) */
418   Symbol_value(S(star)) = STACK_1;                   /* (SETQ * val1) */
419   /* print values to ostream := value from *STANDARD-OUTPUT**/
420   STACK_(1+2) = var_stream(S(standard_output),strmflags_wr_ch_B);
421  #if 0
422   if (mconsp(STACK_0)) {
423     while (1) {
424       var object valsr = STACK_0;
425       STACK_0 = Cdr(valsr);
426       terpri(&STACK_(1+2));
427       prin1(&STACK_(1+2),Car(valsr)); /* print next value */
428       /* ';' as separator before end of line: */
429       if (matomp(STACK_0))
430         break;
431       write_ascii_char(&STACK_(1+2),' ');
432       write_ascii_char(&STACK_(1+2),';');
433     }
434   }
435  #else
436   /* avoid unnecessary empty line between input and output:
437    (There still appears an unnecessary empty line on the screen,
438    if stdin is attached to the terminal and stdout is a pipe, that
439    in the end goes to the terminal again - i.e. via '| tee logfile'.
440    In this case we have to - because of 'logfile' - print an NL to
441    stdout, and because stdin prints an NL at the end of line
442    automatically, this new line really cannot be avoided.) */
443   fresh_line(&STACK_(1+2));     /* (fresh-line ostream) */
444   if (mconsp(STACK_0)) {
445     while (1) {
446       var object valsr = STACK_0;
447       STACK_0 = Cdr(valsr);
448       prin1(&STACK_(1+2),Car(valsr)); /* print next value */
449       /* ';' as separator before end of line: */
450       if (matomp(STACK_0))
451         break;
452       write_ascii_char(&STACK_(1+2),' ');
453       write_ascii_char(&STACK_(1+2),';');
454       terpri(&STACK_(1+2));
455     }
456   }
457  #endif
458   elastic_newline(&STACK_(1+2));
459   skipSTACK(4);
460   VALUES1(NIL);
461 }
462 
463 /* Starts the default driver (Read-Eval-Print-Loop)
464  driver(); */
driver(void)465 global void driver (void)
466 {
467   var p_backtrace_t bt_save = back_trace;
468   var struct backtrace_t bt_here;
469   bt_here.bt_next = back_trace;
470   bt_here.bt_function = L(driver);
471   bt_here.bt_stack = STACK STACKop -1;
472   bt_here.bt_num_arg = -1;
473   back_trace = &bt_here;
474   while (1) {
475     var object driverfun = Symbol_value(S(driverstar)); /* value of *DRIVER* */
476     if (nullp(driverfun))
477       break;
478     funcall(driverfun,0);       /* call with 0 arguments */
479   }
480   /* Default-Driver: */
481   Symbol_value(S(break_count)) = Fixnum_0; /* SYS::*BREAK-COUNT* := 0 */
482   { /* then, build up the driver-frame: */
483     var gcv_object_t* top_of_frame = STACK; /* pointer on top of frame */
484     var sp_jmp_buf returner;                /* memorize return point */
485     finish_entry_frame(DRIVER,returner,,;);
486     /* this is the entry point. */
487     while (1) {
488       /* execute (SYS::READ-EVAL-PRINT "> "): */
489       pushSTACK(O(prompt_string)); /* Prompt "> " */
490       funcall(L(read_eval_print),1);
491       if (eq(value1,T))        /* EOF has been read -> terminate loop */
492         break;
493     }
494     skipSTACK(2);               /* skip driver-frame */
495   }
496   back_trace = bt_save;
497 }
498 
499 /* Starts a secondary driver (Read-Eval-Print-Loop)
500  break_driver(continuable_p);
501  > continuable_p == can be continued after the driver finishes
502  can trigger GC */
break_driver(bool continuable_p)503 global maygc void break_driver (bool continuable_p) {
504   if (quit_on_signal_in_progress) /* if we are terminating on sighup, */
505     quit();              /* printing the "exiting" messages will fail */
506   var object driverfun = Symbol_value(S(break_driver)); /* *BREAK-DRIVER* */
507   if (!nullp(driverfun)) {
508     pushSTACK(continuable_p ? T : NIL);
509     funcall(driverfun,1); /* call with CONTINUABLE argument */
510     if (!continuable_p) /* not continuable? */
511       reset(1); /* -> back to the previous REPLoop */
512   } else {
513     var p_backtrace_t bt_save = back_trace;
514     var struct backtrace_t bt_here;
515     bt_here.bt_next = back_trace;
516     bt_here.bt_function = L(initial_break_driver);
517     bt_here.bt_stack = STACK STACKop -1;
518     bt_here.bt_num_arg = -1;
519     back_trace = &bt_here;
520     /* Default-Driver: (CLEAR-INPUT *DEBUG-IO*), since whatever has been
521        typed so far, was not typed in anticipation of this error */
522     Symbol_value(S(terminal_read_stream)) = unbound;
523     Symbol_value(S(terminal_read_open_object)) = unbound;
524     clear_input(var_stream(S(debug_io),strmflags_rd_ch_B|strmflags_wr_ch_B));
525     /* SYS::*BREAK-COUNT* increase: */
526     dynamic_bind(S(break_count),fixnum_inc(Symbol_value(S(break_count)),1));
527     if (!posfixnump(Symbol_value(S(break_count)))) /* should be Fixnum >=0 */
528       Symbol_value(S(break_count)) = Fixnum_0; /* oops - fix it! */
529     { /* bind *STANDARD-INPUT* and *STANDARD-OUTPUT* to *DEBUG-IO* */
530       var object stream =
531         var_stream(S(debug_io),strmflags_rd_ch_B|strmflags_wr_ch_B);
532       dynamic_bind(S(standard_input),stream);
533       dynamic_bind(S(standard_output),stream);
534     }
535     dynamic_bind(S(print_escape),T);     /* bind *PRINT-ESCAPE* to T */
536     dynamic_bind(S(print_readably),NIL); /* bind *PRINT-READABLY* to NIL */
537     { /* make prompt:
538          (format nil "~S. Break> " SYS::*BREAK-COUNT*)
539          ==
540          (with-output-to-string (s)
541            (prin1 SYS::*BREAK-COUNT* s) (write-string ". Break> " s))
542          ==
543          (let ((s (make-string-output-stream)))
544            (prin1 SYS::*BREAK-COUNT* s) (write-string ". Break> " s)
545            (get-output-stream-string s)) */
546       pushSTACK(make_string_output_stream());
547       prin1(&STACK_0,Symbol_value(S(break_count)));
548       write_sstring(&STACK_0,O(breakprompt_string));
549       STACK_0 = get_output_stream_string(&STACK_0);
550     }
551     { /* make driver-frame: */
552       var gcv_object_t* top_of_frame = STACK; /* pointer over frame */
553       var sp_jmp_buf returner; /* return point */
554       finish_entry_frame(DRIVER,returner,,;);
555       /* re-entry point is here */
556       while (1) {
557         /* (SYS::READ-EVAL-PRINT Prompt) */
558         pushSTACK(STACK_(0+2)); /* Prompt "nnn. Break> " */
559         funcall(L(read_eval_print),1);
560         if (eq(value1,T)) /* EOF -> finish loop */
561           break;
562       }
563       if (!continuable_p) { /* not continuable? */
564         back_trace = bt_save;
565         unwind(); reset(1); /* -> back to the previous REPLoop */
566       }
567       skipSTACK(1+2); /* dissolve driver frame, forget prompt */
568       dynamic_unbind(S(print_readably));
569       dynamic_unbind(S(print_escape));
570       dynamic_unbind(S(standard_output));
571       dynamic_unbind(S(standard_input));
572       dynamic_unbind(S(break_count));
573     }
574     back_trace = bt_save;
575   }
576 }
577 
578 LISPFUNN(initial_break_driver,1)
579 {
580   break_driver(!nullp(popSTACK()));
581   VALUES1(NIL);
582 }
583 
584 LISPFUNN(load,1)
585 /* (LOAD filename), more primitive version than in CLTL p. 426
586    method:
587    (defun load (filename)
588      (let ((stream (open filename))
589            (end-of-file "EOF")) ; nonrecurring object
590        (loop
591          (let ((obj (read stream nil end-of-file)))
592            (when (eql obj end-of-file) (return))
593            (if (compiled-function-p obj) (funcall obj) (eval obj))))
594        (close stream)
595        t)) */
596 {
597   funcall(L(open),1);           /* (OPEN filename) */
598   pushSTACK(value1);            /* save stream */
599   while (1) {
600     var object obj = stream_read(&STACK_0,NIL,NIL); /* read object */
601     if (eq(obj,eof_value))                          /* EOF -> done */
602       break;
603     if (closurep(obj)) {
604       funcall(obj,0);     /* call closure (probably compiled closure) */
605     } else {
606       eval_noenv(obj);          /* evaluate other form */
607     }
608   }
609   builtin_stream_close(&STACK_0,0); /* close stream */
610   skipSTACK(1); VALUES1(T);
611 }
612 
613 /* -----------------------------------------------------------------------
614  Auxiliary functions for debugger and stepper
615 
616  The following functions climb around in the stack, but will never
617  trespass a driver-frame or the upper end of the stack.
618  Valid "stackpointers" are in this context pointers to stack elements or
619  frames, if there is neither the end of stack nor a driver-frame.
620  Modus 1: all stack items
621  Modus 2: frames
622  Modus 3: lexical frames: frame-info has FRAME_BIT = 1 and
623           (SKIP2_BIT = 1 or ENTRYPOINT_BIT = 0 or BLOCKGO_BIT = 1)
624  Modus 4: EVAL- and APPLY-frames: frame-info = [TRAPPED_]EVAL/APPLY_FRAME_INFO
625  Modus 5: APPLY-frames: frame-info = [TRAPPED_]APPLY_FRAME_INFO
626 
627  Macro: tests, if FRAME has reached stack end. */
628 #define stack_upend_p()  \
629   (   (gcv_object_t*)STACK_start cmpSTACKop FRAME                        \
630    || (framecode(FRAME_(0)) == DRIVER_frame_info) /* driver-frame = stack end */ \
631    || ((framepointerp(Symbol_value(S(frame_limit_up))))              \
632        && (uTheFramepointer(Symbol_value(S(frame_limit_up))) cmpSTACKop FRAME) /* FRAME > *frame-limit-up* ? */))
633 #define stack_downend_p()  \
634   (   FRAME cmpSTACKop STACK                                            \
635    || (framecode(FRAME_(0)) == DRIVER_frame_info) /* driver-frame = stack end */ \
636    || ((framepointerp(Symbol_value(S(frame_limit_down))))            \
637        && (FRAME cmpSTACKop uTheFramepointer(Symbol_value(S(frame_limit_down)))) /* FRAME < *frame-limit-down* ? */))
638 
639 /* Macro: Tests, if FRAME points to a frame.
640  first approximation:
641  #define frame_p()  (!( (as_oint(FRAME_(0)) & wbit(frame_bit_o)) ==0))
642  in second approximation, considering the frames with Skip2-bit: */
643 #define frame_p()  framep(FRAME)
framep(gcv_object_t * FRAME)644 local bool framep (gcv_object_t* FRAME)
645 {
646   /* a normal lisp object is not a frame: */
647   if ((as_oint(FRAME_(0)) & wbit(frame_bit_o)) ==0)
648     return false;
649   /* if a frame starts at FRAME_(-1) without Skip2-bit,
650      then FRAME_(0) is part of this frame, which means,
651      it is not itself the start of a frame: */
652   if (   (!(FRAME==STACK))      /* do not trespass the STACK borders! */
653       && (framecode(FRAME_(-1)) < skip2_limit_t)
654       && framep(FRAME STACKop -1))
655     return false;
656   return true;                  /* else, a frame starts here. */
657 }
658 
659 /* Macro: decreases FRAME down to the next frame. */
660 #define next_frame_down()  do { FRAME skipSTACKop -1; } while (!frame_p())
661 
662 /* Macro: Tests, if the frame at FRAME is a lexical frame. */
663 #ifdef entrypoint_bit_t
664 #define lexical_frame_p()                                  \
665   (   (framecode(FRAME_(0)) >= skip2_limit_t)              \
666    || ( (as_oint(FRAME_(0)) & wbit(entrypoint_bit_o)) ==0) \
667    || blockgo_frame_p(framecode(FRAME_(0)))                \
668   )
669 #else
670 #define lexical_frame_p()                                  \
671   (/* (framecode(FRAME_(0)) >= skip2_limit_t)              \
672    || */ (framecode(FRAME_(0)) >= entrypoint_limit_t)      \
673    || blockgo_frame_p(framecode(FRAME_(0)))                \
674   )
675 #endif
blockgo_frame_p(fcint frame_info)676 local bool blockgo_frame_p(fcint frame_info)
677 {
678   switch (frame_info) {
679     case IBLOCK_frame_info:
680     case ITAGBODY_frame_info:
681     case NESTED_IBLOCK_frame_info:
682     case NESTED_ITAGBODY_frame_info:
683     case CBLOCK_CTAGBODY_frame_info:
684       return true;
685     default:
686       return false;
687   }
688 }
689 
690 /* Macro: Tests, if the frame at FRAME is an EVAL/APPLY frame. */
691 #define evalapply_frame_p()  \
692   ((framecode(FRAME_(0)) & ~(bit(eval_bit_t)|bit(trapped_bit_t))) == \
693    ((EVAL_frame_info|APPLY_frame_info) & ~(bit(eval_bit_t)|bit(trapped_bit_t))))
694 
695 /* Macro: Tests, if the frame at FRAME is an APPLY frame. */
696 #define apply_frame_p()  \
697   ((framecode(FRAME_(0)) & ~bit(trapped_bit_t)) == (APPLY_frame_info & ~bit(trapped_bit_t)))
698 
699 /* UP: jumps up one stackitem */
frame_up_1(gcv_object_t * stackptr)700 local gcv_object_t* frame_up_1 (gcv_object_t* stackptr)
701 {
702   var gcv_object_t* FRAME = stackptr;
703   if (frame_p())
704     FRAME = topofframe(FRAME_(0)); /* Pointer to top of frame */
705   else
706     FRAME skipSTACKop 1;        /* pointer to next object */
707   return (stack_upend_p() ? stackptr : FRAME);
708 }
709 
710 /* UP: jumpts down one stackitem */
frame_down_1(gcv_object_t * stackptr)711 local gcv_object_t* frame_down_1 (gcv_object_t* stackptr)
712 {
713   var gcv_object_t* FRAME = stackptr;
714   next_frame_down();          /* search next frame below */
715   if (!(topofframe(FRAME_(0)) == stackptr)) /* not directly below stackptr? */
716     FRAME = stackptr STACKop -1;
717   return (stack_downend_p() ? stackptr : FRAME);
718 }
719 
720 /* UP: jumps up to frame after next frame */
frame_up_2(gcv_object_t * stackptr)721 local gcv_object_t* frame_up_2 (gcv_object_t* stackptr)
722 {
723   var gcv_object_t* FRAME = stackptr;
724   if (frame_p())
725     FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
726   else
727     FRAME skipSTACKop 1;        /* pointer to next object */
728   while (1) {
729     if (stack_upend_p())
730       return stackptr;
731     if (as_oint(FRAME_(0)) & wbit(frame_bit_o))
732       return FRAME;
733     FRAME skipSTACKop 1;
734   }
735 }
736 
737 /* UP: jumps down to frame after next frame */
frame_down_2(gcv_object_t * stackptr)738 local gcv_object_t* frame_down_2 (gcv_object_t* stackptr)
739 {
740   var gcv_object_t* FRAME = stackptr;
741   next_frame_down();          /* search next frame below */
742   return (stack_downend_p() ? stackptr : FRAME);
743 }
744 
745 /* UP: jumps to next higher lexical frame */
frame_up_3(gcv_object_t * stackptr)746 local gcv_object_t* frame_up_3 (gcv_object_t* stackptr)
747 {
748   var gcv_object_t* FRAME = stackptr;
749   if (frame_p())
750     FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
751   else
752     FRAME skipSTACKop 1;      /* pointer to next object */
753   while (1) {
754     if (stack_upend_p())
755       return stackptr;
756     if (frame_p()) {
757       if (lexical_frame_p())
758         return FRAME;
759       FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
760     } else {
761       FRAME skipSTACKop 1;
762     }
763   }
764 }
765 
766 /* UP: jumps to next lower lexical frame */
frame_down_3(gcv_object_t * stackptr)767 local gcv_object_t* frame_down_3 (gcv_object_t* stackptr)
768 {
769   var gcv_object_t* FRAME = stackptr;
770   while (1) {
771     next_frame_down();        /* search next frame below */
772     if (stack_downend_p())
773       return stackptr;
774     if (lexical_frame_p())
775       break;
776   }
777   return FRAME;
778 }
779 
780 /* UP: jumps to next higher EVAL/APPLY-frame */
frame_up_4(gcv_object_t * stackptr)781 local gcv_object_t* frame_up_4 (gcv_object_t* stackptr)
782 {
783   var gcv_object_t* FRAME = stackptr;
784   if (frame_p())
785     FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
786   else
787     FRAME skipSTACKop 1;      /* pointer to next object */
788   while (1) {
789     if (stack_upend_p())
790       return stackptr;
791     if (frame_p()) {
792       if (evalapply_frame_p())
793         return FRAME;
794       FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
795     } else {
796       FRAME skipSTACKop 1;
797     }
798   }
799 }
800 
801 /* UP: jumpt to next lower EVAL/APPLY-frame */
frame_down_4(gcv_object_t * stackptr)802 local gcv_object_t* frame_down_4 (gcv_object_t* stackptr)
803 {
804   var gcv_object_t* FRAME = stackptr;
805   while (1) {
806     next_frame_down();        /* search next frame below */
807     if (stack_downend_p())
808       return stackptr;
809     if (evalapply_frame_p())
810       break;
811   }
812   return FRAME;
813 }
814 
815 /* UP: jumps to next higher APPLY-frame */
frame_up_5(gcv_object_t * stackptr)816 local gcv_object_t* frame_up_5 (gcv_object_t* stackptr)
817 {
818   var gcv_object_t* FRAME = stackptr;
819   if (frame_p())
820     FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
821   else
822     FRAME skipSTACKop 1;      /* pointer to next object */
823   while (1) {
824     if (stack_upend_p())
825       return stackptr;
826     if (frame_p()) {
827       if (apply_frame_p())
828         return FRAME;
829       FRAME = topofframe(FRAME_(0)); /* pointer top of frame */
830     } else {
831       FRAME skipSTACKop 1;
832     }
833   }
834 }
835 
836 /* UP: jumps to next lower APPLY-frame */
frame_down_5(gcv_object_t * stackptr)837 local gcv_object_t* frame_down_5 (gcv_object_t* stackptr)
838 {
839   var gcv_object_t* FRAME = stackptr;
840   while (1) {
841     next_frame_down();        /* search next frame below */
842     if (stack_downend_p())
843       return stackptr;
844     if (apply_frame_p())
845       break;
846   }
847   return FRAME;
848 }
849 
850 /* type of a pointer to a climb-up resp. climb-down routine: */
851 typedef gcv_object_t* (*climb_fun_t) (gcv_object_t* stackptr);
852 
853 local const climb_fun_t frame_up_table[] =
854   { &frame_up_1, &frame_up_2, &frame_up_3, &frame_up_4, &frame_up_5, };
855 local const climb_fun_t frame_down_table[] =
856   { &frame_down_1, &frame_down_2, &frame_down_3, &frame_down_4, &frame_down_5, };
857 
858 /* UP: checks and decodes the mode-argument.
859  test_mode_arg(table)
860  > STACK_0: mode
861  > table: table of routines for climbing up resp. climbing down
862  < result: routine for climbing up resp. climbing down
863  increases STACK by 1 */
test_mode_arg(const climb_fun_t * table)864 local climb_fun_t test_mode_arg (const climb_fun_t* table) {
865   var object arg = popSTACK();
866   var uintV mode;
867   if (   !(posfixnump(arg)
868       && ((mode = posfixnum_to_V(arg)) > 0)
869       && (mode<=5))) {
870     pushSTACK(arg);                /* TYPE-ERROR slot DATUM */
871     pushSTACK(O(type_climb_mode)); /* TYPE-ERROR slot EXPECTED-TYPE */
872     pushSTACK(arg);
873     pushSTACK(TheSubr(subr_self)->name);
874     error(type_error,GETTEXT("~S: bad frame climbing mode ~S"));
875   }
876   return table[mode-1];
877 }
878 
879 /* UP: checks a frame-pointer-argument.
880  test_framepointer_arg()
881  > STACK_0: Lisp object, should be a frame-pointer
882  < result: frame-pointer
883  increases STACK by 1 */
test_framepointer_arg(void)884 local gcv_object_t* test_framepointer_arg (void)
885 {
886   var object arg = popSTACK();
887   if (!framepointerp(arg)) {
888     pushSTACK(arg);              /* TYPE-ERROR slot DATUM */
889     pushSTACK(S(frame_pointer)); /* TYPE-ERROR slot EXPECTED-TYPE */
890     pushSTACK(arg);
891     pushSTACK(TheSubr(subr_self)->name);
892     error(type_error,GETTEXT("~S: ~S is not a stack pointer"));
893   }
894   return uTheFramepointer(arg);
895 }
896 
897 /* climb n times or as far as possible, according to table
898  > STACK_0: mode
899  > STACK_1: frame pointer
900  > STACK_2: indicator, how far to climb
901  < value1: new frame pointer
902  removes 3 elements from STACK
903  can trigger GC*/
climb_stack(const climb_fun_t * table)904 local maygc Values climb_stack (const climb_fun_t* table) {
905   climb_fun_t climber = test_mode_arg(table);
906   gcv_object_t* stackptr = test_framepointer_arg();
907   object repeat_arg = popSTACK();
908   if (uint32_p(repeat_arg)) {
909     uint32 count = I_to_uint32(repeat_arg);
910     while (count--) stackptr = (*climber)(stackptr);
911   } else while (1) { /* climb as far as possible: */
912     gcv_object_t* next_stackptr = (*climber)(stackptr);
913     if (next_stackptr == stackptr)
914       break;
915     stackptr = next_stackptr;
916   }
917   VALUES1(make_framepointer(stackptr));
918 }
919 
920 LISPFUNN(frame_up,3)
921 { /* (SYS::FRAME-UP n framepointer mode)
922      returns the frame-pointer increased by n or the top one. */
923   climb_stack(frame_up_table);
924 }
925 
926 LISPFUNN(frame_down,3)
927 { /* (SYS::FRAME-DOWN n framepointer mode)
928      returns the frame-pointer decreased by n or the bottom one. */
929   climb_stack(frame_down_table);
930 }
931 
932 LISPFUNN(the_frame,0)
933 { /* (SYS::THE-FRAME) returns the current stackpointer as frame-pointer. */
934   var gcv_object_t* stackptr = STACK;
935   stackptr = frame_up_2(stackptr); /* up to the next higher frame */
936   VALUES1(make_framepointer(stackptr));
937 }
938 
939 /* UP: activates the same lexical environment, that was active at
940  framepointer STACK_0.
941  same_env_as();
942  increases STACK by 1, constructs an ENV5-Frame on top of the STACK */
same_env_as(void)943 local void same_env_as (void)
944 {
945   var gcv_object_t* FRAME = test_framepointer_arg();
946   /* 5 Environments still "empty": */
947   var object found_var_env = nullobj;
948   var object found_fun_env = nullobj;
949   var object found_block_env = nullobj;
950   var object found_go_env = nullobj;
951   var object found_decl_env = nullobj;
952   /* and fill: */
953   while (1) {
954     /* search at FRAME downwards for ENV-frames: */
955     while (1) {
956       FRAME skipSTACKop -1;
957       if (FRAME==STACK)       /* done? */
958         goto end;
959       if (   frame_p()
960           && (framecode(FRAME_(0)) >= skip2_limit_t)
961           && (!( (as_oint(FRAME_(0)) & wbit(envbind_bit_o)) ==0)))
962         break;
963     }
964     /* found next ENV-frame.
965        its contents fills the empty components of env: */
966     switch (framecode(FRAME_(0)) & envbind_case_mask_t) {
967       case (ENV1V_frame_info & envbind_case_mask_t): /* 1 VAR_ENV */
968         if (eq(found_var_env,nullobj)) { found_var_env = FRAME_(1); }
969         break;
970       case (ENV1F_frame_info & envbind_case_mask_t): /* 1 FUN_ENV */
971         if (eq(found_fun_env,nullobj)) { found_fun_env = FRAME_(1); }
972         break;
973       case (ENV1B_frame_info & envbind_case_mask_t): /* 1 BLOCK_ENV */
974         if (eq(found_block_env,nullobj)) { found_block_env = FRAME_(1); }
975         break;
976       case (ENV1G_frame_info & envbind_case_mask_t): /* 1 GO_ENV */
977         if (eq(found_go_env,nullobj)) { found_go_env = FRAME_(1); }
978         break;
979       case (ENV1D_frame_info & envbind_case_mask_t): /* 1 DECL_ENV */
980         if (eq(found_decl_env,nullobj)) { found_decl_env = FRAME_(1); }
981         break;
982       case (ENV2VD_frame_info & envbind_case_mask_t): /* 1 VAR_ENV and 1 DECL_ENV */
983         if (eq(found_var_env,nullobj)) { found_var_env = FRAME_(1); }
984         if (eq(found_decl_env,nullobj)) { found_decl_env = FRAME_(2); }
985         break;
986       case (ENV5_frame_info & envbind_case_mask_t): /* all 5 environments */
987         if (eq(found_var_env,nullobj)) { found_var_env = FRAME_(1); }
988         if (eq(found_fun_env,nullobj)) { found_fun_env = FRAME_(2); }
989         if (eq(found_block_env,nullobj)) { found_block_env = FRAME_(3); }
990         if (eq(found_go_env,nullobj)) { found_go_env = FRAME_(4); }
991         if (eq(found_decl_env,nullobj)) { found_decl_env = FRAME_(5); }
992         break;
993       default: NOTREACHED;
994     }
995     /* if each single environment of env is filled (/=nullobj),
996        the environment is done: */
997     if (   (!eq(found_var_env,nullobj))
998         && (!eq(found_fun_env,nullobj))
999         && (!eq(found_block_env,nullobj))
1000         && (!eq(found_go_env,nullobj))
1001         && (!eq(found_decl_env,nullobj)))
1002       goto done;
1003   }
1004  end:                         /* end of stack is reached. */
1005   /* fetch the remaining environment-components from the current environment: */
1006   if (eq(found_var_env,nullobj)) { found_var_env = aktenv.var_env; }
1007   if (eq(found_fun_env,nullobj)) { found_fun_env = aktenv.fun_env; }
1008   if (eq(found_block_env,nullobj)) { found_block_env = aktenv.block_env; }
1009   if (eq(found_go_env,nullobj)) { found_go_env = aktenv.go_env; }
1010   if (eq(found_decl_env,nullobj)) { found_decl_env = aktenv.decl_env; }
1011  done:
1012   /* construct environment-frame: */
1013   make_ENV5_frame();
1014   /* set current environments: */
1015   aktenv.var_env   = found_var_env  ;
1016   aktenv.fun_env   = found_fun_env  ;
1017   aktenv.block_env = found_block_env;
1018   aktenv.go_env    = found_go_env   ;
1019   aktenv.decl_env  = found_decl_env ;
1020 }
1021 
1022 LISPFUNN(same_env_as,2)
1023 { /* (SYS::SAME-ENV-AS framepointer fun) activates the same lexical
1024      environment, that was active at framepointer, and then calls fun. */
1025   var object fun = popSTACK();
1026   same_env_as();              /* activate environment of framepointer */
1027   funcall(fun,0);               /* call fun */
1028   unwind();                     /* unwind environment-frame */
1029 }
1030 
1031 LISPFUNN(eval_at,2)
1032 { /* (SYS::EVAL-AT framepointer form) activates the same lexical
1033      environment, that was active at framepointer, and evaluates the form. */
1034   var object form = popSTACK();
1035   same_env_as();              /* activate environment of framepointer */
1036   eval(form);                   /* evaluate form */
1037   unwind();                     /* unwind environment-frame */
1038 }
1039 
1040 LISPFUNN(eval_frame_p,1)
1041 { /* (SYS::EVAL-FRAME-P framepointer)
1042      indicates, if framepointer points to an EVAL/APPLY-frame. */
1043   var gcv_object_t* FRAME = test_framepointer_arg();
1044   VALUES_IF(evalapply_frame_p());
1045 }
1046 
1047 LISPFUNN(driver_frame_p,1)
1048 { /* (SYS::DRIVER-FRAME-P framepointer)
1049      indicates, if framepointer points to a driver-frame. */
1050   var gcv_object_t* FRAME = test_framepointer_arg();
1051   VALUES_IF(framecode(FRAME_(0)) == DRIVER_frame_info);
1052 }
1053 
1054 /* error-message, if there is no EVAL/APPLY-frame-pointer.
1055  error_evalframe(obj);
1056  > obj: not an EVAL/APPLY-frame-pointer */
error_evalframe(object obj)1057 local _Noreturn void error_evalframe (object obj) {
1058   pushSTACK(obj);
1059   pushSTACK(TheSubr(subr_self)->name);
1060   error(error_condition,GETTEXT("~S: ~S is not a pointer to an EVAL/APPLY frame"));
1061 }
1062 
1063 LISPFUNN(trap_eval_frame,2)
1064 { /* (SYS::TRAP-EVAL-FRAME framepointer flag) switches the breakpoint at
1065      the specified EVAL/APPLY-frame on and off according to flag. */
1066   var object flag = popSTACK();
1067   var object frame = popSTACK();
1068   if (!framepointerp(frame))
1069     error_evalframe(frame);
1070   var gcv_object_t* FRAME = uTheFramepointer(frame);
1071   if (!evalapply_frame_p())
1072     error_evalframe(frame);
1073   /* FRAME points to the EVAL/APPLY-frame. */
1074   if (!nullp(flag)) {
1075     /* switch on breakpoint */
1076     *(oint*)(&FRAME_(0)) |= wbit(trapped_bit_o);
1077   } else {
1078     /* switch off breakpoint */
1079     *(oint*)(&FRAME_(0)) &= ~wbit(trapped_bit_o);
1080   }
1081   VALUES1(frame);
1082 }
1083 
1084 LISPFUNN(redo_eval_frame,1)
1085 { /* (SYS::REDO-EVAL-FRAME framepointer) unwinds up to the specified
1086      EVAL/APPLY-frame and restarts to execute it. */
1087   var object frame = popSTACK();
1088   if (!framepointerp(frame))
1089     error_evalframe(frame);
1090   var gcv_object_t* FRAME = uTheFramepointer(frame);
1091   if (!evalapply_frame_p())
1092     error_evalframe(frame);
1093   /* FRAME points to the EVAL/APPLY-frame. */
1094   VALUES0;
1095   /* unwind everything up to the EVAL/APPLY-frame, then jump there */
1096   unwind_upto(FRAME);
1097 }
1098 
1099 LISPFUNN(return_from_eval_frame,2)
1100 { /* (SYS::RETURN-FROM-EVAL-FRAME framepointer form)
1101      unwind up to the specified EVAL/APPLY-frame and return as its values
1102      all values of the evaluation of the specified form. */
1103   var object form = popSTACK();
1104   var object frame = popSTACK();
1105   if (!framepointerp(frame))
1106     error_evalframe(frame);
1107   var gcv_object_t* FRAME = uTheFramepointer(frame);
1108   if (!evalapply_frame_p())
1109     error_evalframe(frame);
1110   /* FRAME points to the EVAL/APPLY-frame. */
1111   VALUES1(form);
1112   /* unwind everything up to the EVAL/APPLY-frame, jump there */
1113   unwind_upto(FRAME);
1114 }
1115 
1116 /* -----------------------------------------------------------------------
1117  Debug aux
1118 
1119  Returns the top-of-frame of a back_trace element. */
top_of_back_trace_frame(const struct backtrace_t * bt)1120 global gcv_object_t* top_of_back_trace_frame (const struct backtrace_t *bt) {
1121   var gcv_object_t* stack = bt->bt_stack;
1122   var object fun = bt->bt_function;
1123   if (fsubrp(fun)) { /* FSUBR */
1124     var uintW numreq;
1125     var uintW numopt;
1126     var uintW body_flag;
1127     switch ((uintW)posfixnum_to_V(TheFsubr(fun)->argtype)) {
1128       case fsubr_argtype_1_0_nobody: numreq = 1; numopt = 0; body_flag=0; break;
1129       case fsubr_argtype_2_0_nobody: numreq = 2; numopt = 0; body_flag=0; break;
1130       case fsubr_argtype_1_1_nobody: numreq = 1; numopt = 1; body_flag=0; break;
1131       case fsubr_argtype_2_1_nobody: numreq = 2; numopt = 1; body_flag=0; break;
1132       case fsubr_argtype_0_body: numreq = 0; numopt = 0; body_flag = 1; break;
1133       case fsubr_argtype_1_body: numreq = 1; numopt = 0; body_flag = 1; break;
1134       case fsubr_argtype_2_body: numreq = 2; numopt = 0; body_flag = 1; break;
1135       default: NOTREACHED;
1136     }
1137     return stack STACKop (numreq + numopt + body_flag);
1138   }
1139   if (subrp(fun)) /* SUBR */
1140     return stack STACKop (TheSubr(fun)->req_count + TheSubr(fun)->opt_count
1141                           + TheSubr(fun)->key_count);
1142   if (closurep(fun)) {
1143     var object codevec = TheClosure(fun)->clos_codevec;
1144     if (simple_bit_vector_p(Atype_8Bit,codevec)) { /* Compiled Closure */
1145       return stack STACKop (TheCodevec(codevec)->ccv_numreq
1146                             + TheCodevec(codevec)->ccv_numopt
1147                             + (TheCodevec(codevec)->ccv_flags & bit(0) ? 1 : 0)
1148                             + (TheCodevec(codevec)->ccv_flags & bit(7)
1149                                ? TheCodevec(codevec)->ccv_numkey : 0));
1150     } else /* Interpreted Closure */
1151       return stack;
1152   }
1153   /* Only SUBRs and functions occur as bt_function. */
1154   NOTREACHED;
1155 }
1156 
1157 /* print one backtrace object
1158  > stream_ : lisp stream where the object is printed
1159  > bt : the backtrace object to print
1160  > index : the backtrace depth
1161  can trigger GC */
print_back_trace(const gcv_object_t * stream_,const struct backtrace_t * bt,uintL index)1162 local maygc void print_back_trace (const gcv_object_t* stream_,
1163                                    const struct backtrace_t *bt, uintL index) {
1164   write_ascii_char(stream_,'<');
1165   prin1(stream_,fixnum(index));
1166   write_ascii_char(stream_,'/');
1167   prin1(stream_,fixnum(STACK_item_count(bt->bt_stack,
1168                                         (gcv_object_t*)STACK_start)));
1169   write_ascii_char(stream_,'>');
1170   write_ascii_char(stream_,' ');
1171   prin1(stream_,bt->bt_function);
1172   if (bt->bt_num_arg >= 0) {
1173     write_ascii_char(stream_,' ');
1174     prin1(stream_,fixnum(bt->bt_num_arg));
1175   }
1176 }
1177 /* print several backtrace objects, up to FRAME
1178  > stream_ : lisp stream where the object is printed
1179  < FRAME : stack pointer - the limit for printing the stack
1180  > bt : the first backtrace object to print
1181  > index : the backtrace depth
1182  < bt : the next backtrace depth to be printed
1183  < index : the next backtrace depth
1184  can trigger GC */
print_bt_to_frame(const gcv_object_t * stream_,const gcv_object_t * FRAME,p_backtrace_t * bt_,uintL * index)1185 local maygc void print_bt_to_frame (const gcv_object_t* stream_,
1186                                     const gcv_object_t* FRAME,
1187                                     p_backtrace_t *bt_,
1188                                     uintL *index) {
1189   while (bt_beyond_stack_p(*bt_,FRAME)) {
1190     print_back_trace(stream_,*bt_,++(*index));
1191     terpri(stream_);
1192     *bt_ = (*bt_)->bt_next;
1193   }
1194 }
1195 
1196 /* UP: prints the stackitem FRAME_(0) in detail to the stream
1197  and returns the next higher stackptr.
1198  print_stackitem(&stream,FRAME)
1199  can trigger GC */
print_stackitem(const gcv_object_t * stream_,gcv_object_t * FRAME)1200 local maygc gcv_object_t* print_stackitem (const gcv_object_t* stream_,
1201                                            gcv_object_t* FRAME)
1202 {
1203   if (!frame_p()) { /* no frame, normal LISP-object */
1204     write_sstring(stream_,O(showstack_string_lisp_obj)); /* "- " */
1205     var object obj = FRAME_(0);
1206    #if !defined(NO_symbolflags)
1207     switch (typecode(obj)) {  /* poss. remove symbol-flags */
1208       case_symbolflagged: obj = symbol_without_flags(obj);
1209       default: break;
1210     }
1211    #endif
1212     prin1(stream_,obj);       /* print LISP-object */
1213     return FRAME STACKop 1;
1214   } else { /* met frame */
1215     write_ascii_char(stream_,'[');
1216     prin1(stream_,fixnum(STACK_item_count(FRAME,(gcv_object_t*)STACK_start)));
1217     write_ascii_char(stream_,']');
1218     write_ascii_char(stream_,' ');
1219     var gcv_object_t* FRAME_top = topofframe(FRAME_(0)); /* top of frame */
1220     switch (framecode(FRAME_(0))) { /* according to frametype */
1221       case TRAPPED_APPLY_frame_info: {
1222         write_sstring(stream_,CLSTEXT("APPLY frame with breakpoint for call "));
1223       } goto APPLY_frame;
1224       case APPLY_frame_info: {
1225         write_sstring(stream_,CLSTEXT("APPLY frame for call "));
1226        APPLY_frame:
1227         /* print function name and arguments: */
1228         write_ascii_char(stream_,'('); /* print '(' */
1229         prin1(stream_,TheIclosure(FRAME_(frame_closure))->clos_name); /* print name */
1230         {
1231           var gcv_object_t* argptr = FRAME_top;
1232           var uintL count = STACK_item_count(FRAME STACKop frame_args,FRAME_top);
1233           dotimesL(count,count, {
1234             write_ascii_char(stream_,' ');  /* print ' ' */
1235             write_ascii_char(stream_,'\''); /* print "'" */
1236             prin1(stream_,NEXT(argptr));    /* print next argument */
1237           });
1238         }
1239         write_ascii_char(stream_,')'); /* print ')' */
1240       } break;
1241       case TRAPPED_EVAL_frame_info: {
1242         write_sstring(stream_,CLSTEXT("EVAL frame with breakpoint for form "));
1243       } goto EVAL_frame;
1244       case EVAL_frame_info: {
1245         write_sstring(stream_,CLSTEXT("EVAL frame for form "));
1246        EVAL_frame:
1247         prin1(stream_,FRAME_(frame_form)); /* print form */
1248       } break;
1249       case DYNBIND_frame_info: { /* dynamic variable binding frames: */
1250         write_sstring(stream_,CLSTEXT("frame binding variables (~ = dynamically):"));
1251         /* print bindings: */
1252         FRAME skipSTACKop 1;
1253         while (FRAME != FRAME_top) {
1254           /* print binding of Symbol FRAME_(0) to value FRAME_(1): */
1255           write_sstring(stream_,O(showstack_string_bindung)); /* "␤  | " */
1256           write_ascii_char(stream_,'~'); /* print '~' */
1257           write_ascii_char(stream_,' '); /* print ' ' */
1258           prin1(stream_,FRAME_(0));      /* print symbol */
1259           write_sstring(stream_,O(showstack_string_zuord)); /* " <--> " */
1260           prin1(stream_,FRAME_(1)); /* print value */
1261           FRAME skipSTACKop 2;
1262         }
1263       } break;
1264      #ifdef HAVE_SAVED_REGISTERS
1265       case CALLBACK_frame_info: { /* callback-register-frames: */
1266         write_sstring(stream_,CLSTEXT("CALLBACK frame"));
1267       } break;
1268      #endif
1269       /* variable- and function binding frames: */
1270       case VAR_frame_info: {
1271         write_sstring(stream_,CLSTEXT("frame binding variables "));
1272        #ifdef NO_symbolflags
1273         prin1(stream_,make_framepointer(FRAME)); /* print frame-pointer */
1274         write_sstring(stream_,CLSTEXT(" binds (~ = dynamically):"));
1275         pushSTACK(FRAME_(frame_next_env)); /* save next environment */
1276         /* print bindings: */
1277         FRAME skipSTACKop frame_bindings;
1278         while (FRAME != FRAME_top) {
1279           if (as_oint(FRAME_(varframe_binding_mark)) & wbit(active_bit_o)) {
1280             /* print binding of symbol FRAME_(1) to value FRAME_(2): */
1281             write_sstring(stream_,O(showstack_string_bindung)); /* "␤  | " */
1282             if (as_oint(FRAME_(varframe_binding_mark)) & wbit(dynam_bit_o))
1283               /* dynamic binding? */
1284               write_ascii_char(stream_,'~'); /* yes -> print '~' */
1285             write_ascii_char(stream_,' ');   /* print ' ' */
1286             /* print symbol: */
1287             prin1(stream_,symbol_without_flags(FRAME_(varframe_binding_sym)));
1288             write_sstring(stream_,O(showstack_string_zuord)); /* " <--> " */
1289             prin1(stream_,FRAME_(varframe_binding_value)); /* print value */
1290           }
1291           FRAME skipSTACKop varframe_binding_size;
1292         }
1293         goto VARFUN_frame_next;
1294        #else
1295         goto VARFUN_frame;
1296        #endif
1297       }
1298       case FUN_frame_info: {
1299         write_sstring(stream_,CLSTEXT("frame binding functions "));
1300         goto VARFUN_frame;
1301        VARFUN_frame: {
1302         prin1(stream_,make_framepointer(FRAME)); /* print frame-pointer */
1303         write_sstring(stream_,CLSTEXT(" binds (~ = dynamically):"));
1304         pushSTACK(FRAME_(frame_next_env)); /* save next environment */
1305         /* print bindings: */
1306         FRAME skipSTACKop frame_bindings;
1307         while (FRAME != FRAME_top) {
1308           if (as_oint(FRAME_(0)) & wbit(active_bit_o)) {
1309             /* print binding of symbol FRAME_(0) to value FRAME_(1): */
1310             write_sstring(stream_,O(showstack_string_bindung)); /* "␤  | " */
1311             if (as_oint(FRAME_(0)) & wbit(dynam_bit_o)) /* bindings dynamic? */
1312               write_ascii_char(stream_,'~'); /* yes -> print '~' */
1313             write_ascii_char(stream_,' ');   /* print ' ' */
1314             prin1(stream_,symbol_without_flags(FRAME_(0))); /* print symbol */
1315             write_sstring(stream_,O(showstack_string_zuord)); /* " <--> " */
1316             prin1(stream_,FRAME_(1)); /* print value */
1317           }
1318           FRAME skipSTACKop 2;
1319         }}
1320        VARFUN_frame_next:
1321         /* print next environment: */
1322         terpri(stream_);
1323         write_sstring(stream_,CLSTEXT("  Next environment: "));
1324         {
1325           var object env = popSTACK(); /* next environment */
1326           if (!simple_vector_p(env)) {
1327             prin1(stream_,env);
1328           } else {
1329             /* next environment is a vector of length 2n+1 */
1330             do {
1331               pushSTACK(env);
1332               var uintL count = floor(Svector_length(env),2); /* = n = number of bindings */
1333               var uintL index = 0;
1334               dotimesL(count,count, {
1335                 write_sstring(stream_,O(showstack_string_bindung)); /* "␤  | " */
1336                 prin1(stream_,TheSvector(STACK_0)->data[index++]); /* print symbol */
1337                 write_sstring(stream_,O(showstack_string_zuord)); /* " <--> " */
1338                 prin1(stream_,TheSvector(STACK_0)->data[index++]); /* print symbol */
1339               });
1340               env = TheSvector(popSTACK())->data[index]; /* last vector-element */
1341             } while (simple_vector_p(env));
1342           }
1343         }
1344       } break;
1345         /* compiled block/tagbody-frames: */
1346       case CBLOCK_CTAGBODY_frame_info: {
1347         if (simple_vector_p(Car(FRAME_(frame_ctag)))) {
1348           /* compiled tagbody-frames: */
1349           write_sstring(stream_,CLSTEXT("compiled tagbody frame for "));
1350           prin1(stream_,Car(FRAME_(frame_ctag))); /* tag-vector */
1351         } else {
1352           /* compiled block-frames: */
1353           write_sstring(stream_,CLSTEXT("compiled block frame for "));
1354           prin1(stream_,Car(FRAME_(frame_ctag))); /* blockname */
1355         }
1356       } break;
1357         /* interpreted block-frames: */
1358       case IBLOCK_frame_info: {
1359         write_sstring(stream_,CLSTEXT("block frame "));
1360       } goto IBLOCK_frame;
1361       case NESTED_IBLOCK_frame_info: {
1362         write_sstring(stream_,CLSTEXT("nested block frame "));
1363       } goto IBLOCK_frame;
1364       IBLOCK_frame: {
1365         pushSTACK(FRAME_(frame_next_env));
1366         prin1(stream_,make_framepointer(FRAME)); /* print frame-pointer */
1367         write_sstring(stream_,CLSTEXT(" for "));
1368         prin1(stream_,FRAME_(frame_name)); /* blockname */
1369       } goto NEXT_ENV;
1370         /* interpreted tagbody-frames: */
1371       case ITAGBODY_frame_info: {
1372         write_sstring(stream_,CLSTEXT("tagbody frame "));
1373       } goto ITAGBODY_frame;
1374       case NESTED_ITAGBODY_frame_info: {
1375         write_sstring(stream_,CLSTEXT("nested tagbody frame "));
1376       } goto ITAGBODY_frame;
1377       ITAGBODY_frame: {
1378         pushSTACK(FRAME_(frame_next_env));
1379         prin1(stream_,make_framepointer(FRAME)); /* print frame-pointer */
1380         write_sstring(stream_,CLSTEXT(" for"));
1381         /* print tags/bodys: */
1382         FRAME skipSTACKop frame_bindings;
1383         while (FRAME != FRAME_top) {
1384           /* print binding of tag FRAME_(0) to body FRAME_(1): */
1385           write_sstring(stream_,O(showstack_string_bindung)); /* "␤  | " */
1386           prin1(stream_,FRAME_(0)); /* print tag */
1387           write_sstring(stream_,O(showstack_string_zuordtag)); /* " --> " */
1388           prin1(stream_,FRAME_(1)); /* print body */
1389           FRAME skipSTACKop 2;
1390         }
1391       } goto NEXT_ENV;
1392       NEXT_ENV: { /* printing of a block- or tagbody-environments STACK_0 */
1393         terpri(stream_);
1394         write_sstring(stream_,CLSTEXT("  Next environment: "));
1395         var object env = popSTACK();
1396         if (!consp(env)) {
1397           prin1(stream_,env);
1398         } else { /* next environment is an Alist */
1399           do {
1400             pushSTACK(Cdr(env));
1401             env = Car(env);
1402             if (atomp(env)) {
1403               pushSTACK(S(show_stack));
1404               error(error_condition,
1405                     GETTEXT("~S: environment is not an association list"));
1406             }
1407             pushSTACK(Cdr(env));
1408             pushSTACK(Car(env));
1409             write_sstring(stream_,O(showstack_string_bindung)); /* "␤  | " */
1410             prin1(stream_,popSTACK());
1411             write_sstring(stream_,O(showstack_string_zuordtag)); /* " --> " */
1412             prin1(stream_,popSTACK());
1413             env = popSTACK();
1414           } while (consp(env));
1415         }
1416       } break;
1417       case CATCH_frame_info: { /* catch-frames: */
1418         write_sstring(stream_,CLSTEXT("catch frame for tag "));
1419         prin1(stream_,FRAME_(frame_tag)); /* tag */
1420       } break;
1421       case HANDLER_frame_info: { /* handler-frames: */
1422         write_sstring(stream_,CLSTEXT("handler frame for conditions"));
1423         var uintL m2 = Svector_length(Car(FRAME_(frame_handlers))); /* 2*m */
1424         var uintL i = 0;
1425         do {
1426           write_ascii_char(stream_,' '); /* print ' ' */
1427           prin1(stream_,TheSvector(Car(FRAME_(frame_handlers)))->data[i]); /* print type i */
1428           i += 2;
1429         } while (i < m2);
1430       } break;
1431       case UNWIND_PROTECT_frame_info: { /* unwind-protect-frames: */
1432         write_sstring(stream_,CLSTEXT("unwind-protect frame"));
1433       } break;
1434       case DRIVER_frame_info: { /* driver-frames: */
1435         terpri(stream_); /* blank line */
1436         write_sstring(stream_,CLSTEXT("driver frame"));
1437       } break;
1438         /* environment-frames: */
1439       case ENV1V_frame_info: {
1440         write_sstring(stream_,CLSTEXT("frame binding environments"));
1441         write_sstring(stream_,O(showstack_string_VENV_frame)); /* "␤  VAR_ENV <--> " */
1442         prin1(stream_,FRAME_(1));
1443       } break;
1444       case ENV1F_frame_info: {
1445         write_sstring(stream_,CLSTEXT("frame binding environments"));
1446         write_sstring(stream_,O(showstack_string_FENV_frame)); /* "␤  FUN_ENV <--> " */
1447         prin1(stream_,FRAME_(1));
1448       } break;
1449       case ENV1B_frame_info: {
1450         write_sstring(stream_,CLSTEXT("frame binding environments"));
1451         write_sstring(stream_,O(showstack_string_BENV_frame)); /* "␤  BLOCK_ENV <--> " */
1452         prin1(stream_,FRAME_(1));
1453       } break;
1454       case ENV1G_frame_info: {
1455         write_sstring(stream_,CLSTEXT("frame binding environments"));
1456         write_sstring(stream_,O(showstack_string_GENV_frame)); /* "␤  GO_ENV <--> " */
1457         prin1(stream_,FRAME_(1));
1458       } break;
1459       case ENV1D_frame_info: {
1460         write_sstring(stream_,CLSTEXT("frame binding environments"));
1461         write_sstring(stream_,O(showstack_string_DENV_frame)); /* "␤  DECL_ENV <--> " */
1462         prin1(stream_,FRAME_(1));
1463       } break;
1464       case ENV2VD_frame_info: {
1465         write_sstring(stream_,CLSTEXT("frame binding environments"));
1466         write_sstring(stream_,O(showstack_string_VENV_frame)); /* "␤  VAR_ENV <--> " */
1467         prin1(stream_,FRAME_(1));
1468         write_sstring(stream_,O(showstack_string_DENV_frame)); /* "␤  DECL_ENV <--> " */
1469         prin1(stream_,FRAME_(2));
1470       } break;
1471       case ENV5_frame_info: {
1472         write_sstring(stream_,CLSTEXT("frame binding environments"));
1473         write_sstring(stream_,O(showstack_string_VENV_frame)); /* "␤  VAR_ENV <--> " */
1474         prin1(stream_,FRAME_(1));
1475         write_sstring(stream_,O(showstack_string_FENV_frame)); /* "␤  FUN_ENV <--> " */
1476         prin1(stream_,FRAME_(2));
1477         write_sstring(stream_,O(showstack_string_BENV_frame)); /* "␤  BLOCK_ENV <--> " */
1478         prin1(stream_,FRAME_(3));
1479         write_sstring(stream_,O(showstack_string_GENV_frame)); /* "␤  GO_ENV <--> " */
1480         prin1(stream_,FRAME_(4));
1481         write_sstring(stream_,O(showstack_string_DENV_frame)); /* "␤  DECL_ENV <--> " */
1482         prin1(stream_,FRAME_(5));
1483       } break;
1484       default:
1485         pushSTACK(S(show_stack));
1486         error(serious_condition,GETTEXT("~S: unknown frame type"));
1487     }
1488     return FRAME_top;         /* pointer top of frame */
1489   }
1490 }
1491 
1492 LISPFUNN(describe_frame,2)
1493 { /* (SYS::DESCRIBE-FRAME stream framepointer) prints in detail the
1494      stackitem, that the pointer points to. */
1495   var gcv_object_t* FRAME = test_framepointer_arg(); /* pointer in the stack */
1496   STACK_0 = check_stream(STACK_0);
1497   fresh_line(&STACK_0);
1498   {
1499     var uintL count = 0;
1500     var p_backtrace_t bt = back_trace;
1501     unwind_back_trace(bt,FRAME STACKop -1);
1502     print_bt_to_frame(&STACK_0,FRAME,&bt,&count);
1503   }
1504   print_stackitem(&STACK_0,FRAME); /* print stack-item */
1505   elastic_newline(&STACK_0);
1506   skipSTACK(1); VALUES0; /* no values */
1507 }
1508 
1509 /* UP: print the stack (up to frame_limit frames, if that is non-0)
1510  frame by frame (moving using frame_up_x) or all stack items if that is NULL.
1511  starting with start_frame or STACK if that is NULL
1512  In debugger, use 'print show_stack(0,0,0)'.
1513  can trigger GC */
show_stack(climb_fun_t frame_up_x,uintL frame_limit,gcv_object_t * start_frame)1514 local inline maygc uintL show_stack (climb_fun_t frame_up_x, uintL frame_limit,
1515                                      gcv_object_t* start_frame)
1516 { /* run along the stack upwards */
1517   var gcv_object_t* FRAME = (start_frame == NULL ? STACK : start_frame);
1518   pushSTACK(var_stream(S(standard_output),strmflags_wr_ch_B));
1519   var gcv_object_t* stream_ = &STACK_0;
1520   var uintL count = 0;
1521   var p_backtrace_t bt = back_trace;
1522   while (!((gcv_object_t*)STACK_start == FRAME)
1523          && (frame_limit==0 || count<frame_limit)) {
1524     fresh_line(stream_);
1525     print_bt_to_frame(stream_,FRAME,&bt,&count);
1526     FRAME = print_stackitem(stream_,FRAME);
1527     elastic_newline(stream_);
1528     if (frame_up_x != NULL) {
1529       var gcv_object_t* next_frame = (*frame_up_x)(FRAME);
1530       if (next_frame == FRAME) break;
1531       FRAME = next_frame;
1532     }
1533   }
1534   skipSTACK(1); /* drop *STANDARD-OUTPUT* */
1535   return count;
1536 }
1537 
1538 LISPFUN(show_stack,seclass_default,0,3,norest,nokey,0,NIL)
1539 { /* (SHOW-STACK mode limit start-frame) print the stack contents. */
1540   var gcv_object_t* start_frame = (missingp(STACK_0) ? (skipSTACK(1), &STACK_1)
1541                                    : test_framepointer_arg());
1542   var uintL frame_limit = (missingp(STACK_0) ? (skipSTACK(1), 0) :
1543                            uint32_p(STACK_0) ? I_to_uint32(popSTACK())
1544                            : (error_uint32(popSTACK()), 0));
1545   var climb_fun_t frame_up_x = (missingp(STACK_0)
1546                                 ? (skipSTACK(1), (climb_fun_t) NULL)
1547                                 : test_mode_arg(&frame_up_table[0]));
1548   VALUES1(UL_to_I(show_stack(frame_up_x,frame_limit,start_frame)));
1549 }
1550 
1551 /* For debugging: From within gdb, type: call gdb_show_stack().
1552    Equivalent to (ext:show-stack) from the Lisp prompt. */
gdb_show_stack(void)1553 global void gdb_show_stack (void) {
1554   pushSTACK(unbound); pushSTACK(unbound); pushSTACK(unbound); C_show_stack();
1555 }
1556 
1557 /* Fore debugging: From within gdb, type: call gdb_disassemble_closure(obj).
1558    Equivalent to (sys::disassemble-closures obj *standard-output*). */
gdb_disassemble_closure(object obj)1559 global void gdb_disassemble_closure (object obj) {
1560   pushSTACK(obj); pushSTACK(Symbol_value(S(standard_output)));
1561   funcall(S(disassemble_closures),2);
1562   pushSTACK(Symbol_value(S(standard_output))); terpri(&STACK_0); skipSTACK(1);
1563 }
1564 
1565 LISPFUNN(crash,0)
1566 { /* (SYSTEM::CRASH) jumps to the debugger sitting in the background. */
1567   abort();
1568   VALUES0;                      /* no values */
1569 }
1570 
1571 LISPFUNN(proom,0)
1572 { /* (SYSTEM::%ROOM), returns 6 values:
1573      - room occupied by LISP-objects (bytes)
1574      - room free for LISP-objects (bytes)
1575      - room statically occupied by LISP-objects (bytes)
1576      - GC count
1577      - total space freed by GC (bytes)
1578      - total time spent in GC (internal time units)
1579      do it in more detail at SPVW_PAGES?? */
1580   pushSTACK(uintM_to_I(used_space()));
1581   pushSTACK(uintM_to_I(free_space()));
1582   pushSTACK(uintM_to_I(static_space()));
1583   pushSTACK(UL_to_I(gc_count));
1584  #ifdef intQsize
1585   pushSTACK(UQ_to_I(gc_space));
1586  #else
1587   pushSTACK(UL2_to_I(gc_space.hi,gc_space.lo));
1588  #endif
1589   pushSTACK(internal_time_to_I(&gc_time));
1590   STACK_to_mv(6);
1591 }
1592 
1593 LISPFUN(gc,seclass_default,0,1,norest,nokey,0,NIL)
1594 { /* execute a GC and return the same values as %ROOM
1595    with an argument, invalidate JITC objects */
1596   var object arg = popSTACK();
1597   PERFORM_GC(gar_col(missingp(arg) ? 0 : 1),true); /* execute GC */
1598   C_proom();
1599 }
1600 
1601 /* rewrite read-form, in collaboration with the terminal-stream?? */
1602