genie-monitor.c
1 //! @file genie-monitor.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2026 J. Marcel van der Veer [algol68g@algol68genie.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! GDB-style monitor for the interpreter.
25
26 // This is a basic monitor for Algol68G. It activates when the interpreter
27 // receives SIGINT (CTRL-C, for instance) or when PROC VOID break, debug or
28 // evaluate is called, or when a runtime error occurs and --debug is selected.
29 // The monitor allows single stepping (unit-wise through serial/enquiry
30 // clauses) and has basic means for inspecting call-frame stack and heap.
31
32 // breakpoint clear [all], clear breakpoints and watchpoint expression.
33 // breakpoint clear breakpoints, clear breakpoints.
34 // breakpoint clear watchpoint, clear watchpoint expression.
35 // breakpoint [list], list breakpoints.
36 // breakpoint 'n' clear, clear breakpoints in line 'n'.
37 // breakpoint 'n' if 'expression', break in line 'n' when expression evaluates to true.
38 // breakpoint 'n', set breakpoints in line 'n'.
39 // breakpoint watch 'expression', break on watchpoint expression when it evaluates to true.
40 // calls [n], print 'n' frames in the call stack (default n=3).
41 // continue, resume, continue execution.
42 // do 'command', exec 'command', pass 'command' to the shell and print return code.
43 // elems [n], print first 'n' elements of rows (default n=24).
44 // evaluate 'expression', x 'expression', print result of 'expression'.
45 // examine 'n', print value of symbols named 'n' in the call stack.
46 // exit, hx, quit, terminates the program.
47 // finish, out, continue execution until current procedure incarnation is finished.
48 // frame 0, set current stack frame to top of frame stack.
49 // frame 'n', set current stack frame to 'n'.
50 // frame, print contents of the current stack frame.
51 // heap 'n', print contents of the heap with address not greater than 'n'.
52 // help [expression], print brief help text.
53 // ht, halts typing to standard output.
54 // list [n], show 'n' lines around the interrupted line (default n=10).
55 // next, continue execution to next interruptable unit (do not enter routine-texts).
56 // prompt 's', set prompt to 's'.
57 // rerun, restart, restarts a program without resetting breakpoints.
58 // reset, restarts a program and resets breakpoints.
59 // rt, resumes typing to standard output.
60 // sizes, print size of memory segments.
61 // stack [n], print 'n' frames in the stack (default n=3).
62 // step, continue execution to next interruptable unit.
63 // until 'n', continue execution until line number 'n' is reached.
64 // where, print the interrupted line.
65 // xref 'n', give detailed information on source line 'n'.
66
67 #include "a68g.h"
68 #include "a68g-conversion.h"
69 #include "a68g-genie.h"
70 #include "a68g-frames.h"
71 #include "a68g-prelude.h"
72 #include "a68g-mp.h"
73 #include "a68g-parser.h"
74 #include "a68g-listing.h"
75 #include "a68g-transput.h"
76
77 #define CANNOT_SHOW " unprintable or uninitialised value"
78 #define MAX_ROW_ELEMS 24
79 #define NOT_A_NUM (-1)
80 #define NO_VALUE " uninitialised value"
81 #define TOP_MODE (A68G_MON (_m_stack)[A68G_MON (_m_sp) - 1])
82 #define LOGOUT_STRING "exit"
83
84 void parse (FILE_T, NODE_T *, int);
85
86 BOOL_T check_initialisation (NODE_T *, BYTE_T *, MOID_T *, BOOL_T *);
87
88 #define SKIP_ONE_SYMBOL(sym) {\
89 while (!IS_SPACE ((sym)[0]) && (sym)[0] != NULL_CHAR) {\
90 (sym)++;\
91 }\
92 while (IS_SPACE ((sym)[0]) && (sym)[0] != NULL_CHAR) {\
93 (sym)++;\
94 }}
95
96 #define SKIP_SPACE(sym) {\
97 while (IS_SPACE ((sym)[0]) && (sym)[0] != NULL_CHAR) {\
98 (sym)++;\
99 }}
100
101 #define CHECK_MON_REF(p, z, m)\
102 if (! INITIALISED (&z)) {\
103 ASSERT (a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s", moid_to_string ((m), MOID_WIDTH, NO_NODE)) >= 0);\
104 monitor_error (NO_VALUE, A68G (edit_line));\
105 QUIT_ON_ERROR;\
106 } else if (IS_NIL (z)) {\
107 ASSERT (a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s", moid_to_string ((m), MOID_WIDTH, NO_NODE)) >= 0);\
108 monitor_error ("accessing NIL name", A68G (edit_line));\
109 QUIT_ON_ERROR;\
110 }
111
112 #define QUIT_ON_ERROR\
113 if (A68G_MON (mon_errors) > 0) {\
114 return;\
115 }
116
117 #define PARSE_CHECK(f, p, d)\
118 parse ((f), (p), (d));\
119 QUIT_ON_ERROR;
120
121 #define SCAN_CHECK(f, p)\
122 scan_sym((f), (p));\
123 QUIT_ON_ERROR;
124
125
126 //! @brief Confirm that we really want to quit.
127
128 BOOL_T confirm_exit (void)
129 {
130 peek_char (A68G_PEEK_RESET);
131 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Terminate %s (yes|no): ", A68G (a68g_cmd_name)) >= 0);
132 WRITELN (A68G_STDOUT, A68G (output_line));
133 char *cmd = read_string_from_tty (NULL);
134 if (TO_UCHAR (cmd[0]) == TO_UCHAR (EOF_CHAR)) {
135 return confirm_exit ();
136 }
137 for (int k = 0; cmd[k] != NULL_CHAR; k++) {
138 cmd[k] = (char) TO_LOWER (cmd[k]);
139 }
140 if (strcmp (cmd, "y") == 0) {
141 return A68G_TRUE;
142 }
143 if (strcmp (cmd, "yes") == 0) {
144 return A68G_TRUE;
145 }
146 if (strcmp (cmd, "n") == 0) {
147 return A68G_FALSE;
148 }
149 if (strcmp (cmd, "no") == 0) {
150 return A68G_FALSE;
151 }
152 return confirm_exit ();
153 }
154
155
156 //! @brief Give a monitor error message.
157
158 void monitor_error (char *msg, char *info)
159 {
160 QUIT_ON_ERROR;
161 A68G_MON (mon_errors)++;
162 a68g_bufcpy (A68G_MON (error_text), msg, BUFFER_SIZE);
163 WRITELN (A68G_STDOUT, A68G (a68g_cmd_name));
164 WRITE (A68G_STDOUT, ": monitor error: ");
165 WRITE (A68G_STDOUT, A68G_MON (error_text));
166 if (info != NO_TEXT) {
167 WRITE (A68G_STDOUT, " (");
168 WRITE (A68G_STDOUT, info);
169 WRITE (A68G_STDOUT, ")");
170 }
171 WRITE (A68G_STDOUT, ".");
172 }
173
174
175 //! @brief Scan symbol from input.
176
177 void scan_sym (FILE_T f, NODE_T * p)
178 {
179 (void) f;
180 (void) p;
181 A68G_MON (symbol)[0] = NULL_CHAR;
182 A68G_MON (attr) = 0;
183 QUIT_ON_ERROR;
184 while (IS_SPACE (A68G_MON (expr)[A68G_MON (pos)])) {
185 A68G_MON (pos)++;
186 }
187 if (A68G_MON (expr)[A68G_MON (pos)] == NULL_CHAR) {
188 A68G_MON (attr) = 0;
189 A68G_MON (symbol)[0] = NULL_CHAR;
190 return;
191 } else if (A68G_MON (expr)[A68G_MON (pos)] == ':') {
192 if (strncmp (&(A68G_MON (expr)[A68G_MON (pos)]), ":=:", 3) == 0) {
193 A68G_MON (pos) += 3;
194 a68g_bufcpy (A68G_MON (symbol), ":=:", BUFFER_SIZE);
195 A68G_MON (attr) = IS_SYMBOL;
196 } else if (strncmp (&(A68G_MON (expr)[A68G_MON (pos)]), ":/=:", 4) == 0) {
197 A68G_MON (pos) += 4;
198 a68g_bufcpy (A68G_MON (symbol), ":/=:", BUFFER_SIZE);
199 A68G_MON (attr) = ISNT_SYMBOL;
200 } else if (strncmp (&(A68G_MON (expr)[A68G_MON (pos)]), ":=", 2) == 0) {
201 A68G_MON (pos) += 2;
202 a68g_bufcpy (A68G_MON (symbol), ":=", BUFFER_SIZE);
203 A68G_MON (attr) = ASSIGN_SYMBOL;
204 } else {
205 A68G_MON (pos)++;
206 a68g_bufcpy (A68G_MON (symbol), ":", BUFFER_SIZE);
207 A68G_MON (attr) = COLON_SYMBOL;
208 }
209 return;
210 } else if (A68G_MON (expr)[A68G_MON (pos)] == QUOTE_CHAR) {
211 A68G_MON (pos)++;
212 BOOL_T cont = A68G_TRUE; int k = 0;
213 while (cont) {
214 while (A68G_MON (expr)[A68G_MON (pos)] != QUOTE_CHAR) {
215 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
216 }
217 if (A68G_MON (expr)[++A68G_MON (pos)] == QUOTE_CHAR) {
218 A68G_MON (symbol)[k++] = QUOTE_CHAR;
219 } else {
220 cont = A68G_FALSE;
221 }
222 }
223 A68G_MON (symbol)[k] = NULL_CHAR;
224 A68G_MON (attr) = ROW_CHAR_DENOTATION;
225 return;
226 } else if (IS_LOWER (A68G_MON (expr)[A68G_MON (pos)])) {
227 int k = 0;
228 while (IS_LOWER (A68G_MON (expr)[A68G_MON (pos)]) || IS_DIGIT (A68G_MON (expr)[A68G_MON (pos)]) || IS_SPACE (A68G_MON (expr)[A68G_MON (pos)])) {
229 if (IS_SPACE (A68G_MON (expr)[A68G_MON (pos)])) {
230 A68G_MON (pos)++;
231 } else {
232 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
233 }
234 }
235 A68G_MON (symbol)[k] = NULL_CHAR;
236 A68G_MON (attr) = IDENTIFIER;
237 return;
238 } else if (IS_UPPER (A68G_MON (expr)[A68G_MON (pos)])) {
239 KEYWORD_T *kw; int k = 0;
240 while (IS_UPPER (A68G_MON (expr)[A68G_MON (pos)])) {
241 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
242 }
243 A68G_MON (symbol)[k] = NULL_CHAR;
244 kw = find_keyword (A68G (top_keyword), A68G_MON (symbol));
245 if (kw != NO_KEYWORD) {
246 A68G_MON (attr) = ATTRIBUTE (kw);
247 } else {
248 A68G_MON (attr) = OPERATOR;
249 }
250 return;
251 } else if (IS_DIGIT (A68G_MON (expr)[A68G_MON (pos)])) {
252 int k = 0;
253 while (IS_DIGIT (A68G_MON (expr)[A68G_MON (pos)])) {
254 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
255 }
256 if (A68G_MON (expr)[A68G_MON (pos)] == 'r') {
257 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
258 while (IS_XDIGIT (A68G_MON (expr)[A68G_MON (pos)])) {
259 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
260 }
261 A68G_MON (symbol)[k] = NULL_CHAR;
262 A68G_MON (attr) = BITS_DENOTATION;
263 return;
264 }
265 if (A68G_MON (expr)[A68G_MON (pos)] != POINT_CHAR && A68G_MON (expr)[A68G_MON (pos)] != 'e' && A68G_MON (expr)[A68G_MON (pos)] != 'E') {
266 A68G_MON (symbol)[k] = NULL_CHAR;
267 A68G_MON (attr) = INT_DENOTATION;
268 return;
269 }
270 if (A68G_MON (expr)[A68G_MON (pos)] == POINT_CHAR) {
271 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
272 while (IS_DIGIT (A68G_MON (expr)[A68G_MON (pos)])) {
273 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
274 }
275 }
276 if (A68G_MON (expr)[A68G_MON (pos)] != 'e' && A68G_MON (expr)[A68G_MON (pos)] != 'E') {
277 A68G_MON (symbol)[k] = NULL_CHAR;
278 A68G_MON (attr) = REAL_DENOTATION;
279 return;
280 }
281 A68G_MON (symbol)[k++] = (char) TO_UPPER (A68G_MON (expr)[A68G_MON (pos)++]);
282 if (A68G_MON (expr)[A68G_MON (pos)] == '+' || A68G_MON (expr)[A68G_MON (pos)] == '-') {
283 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
284 }
285 while (IS_DIGIT (A68G_MON (expr)[A68G_MON (pos)])) {
286 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
287 }
288 A68G_MON (symbol)[k] = NULL_CHAR;
289 A68G_MON (attr) = REAL_DENOTATION;
290 return;
291 } else if (strchr (MONADS, A68G_MON (expr)[A68G_MON (pos)]) != NO_TEXT || strchr (NOMADS, A68G_MON (expr)[A68G_MON (pos)]) != NO_TEXT) {
292 int k = 0;
293 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
294 if (strchr (NOMADS, A68G_MON (expr)[A68G_MON (pos)]) != NO_TEXT) {
295 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
296 }
297 if (A68G_MON (expr)[A68G_MON (pos)] == ':') {
298 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
299 if (A68G_MON (expr)[A68G_MON (pos)] == '=') {
300 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
301 } else {
302 A68G_MON (symbol)[k] = NULL_CHAR;
303 monitor_error ("invalid operator symbol", A68G_MON (symbol));
304 }
305 } else if (A68G_MON (expr)[A68G_MON (pos)] == '=') {
306 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
307 if (A68G_MON (expr)[A68G_MON (pos)] == ':') {
308 A68G_MON (symbol)[k++] = A68G_MON (expr)[A68G_MON (pos)++];
309 } else {
310 A68G_MON (symbol)[k] = NULL_CHAR;
311 monitor_error ("invalid operator symbol", A68G_MON (symbol));
312 }
313 }
314 A68G_MON (symbol)[k] = NULL_CHAR;
315 A68G_MON (attr) = OPERATOR;
316 return;
317 } else if (A68G_MON (expr)[A68G_MON (pos)] == '(') {
318 A68G_MON (pos)++;
319 A68G_MON (attr) = OPEN_SYMBOL;
320 return;
321 } else if (A68G_MON (expr)[A68G_MON (pos)] == ')') {
322 A68G_MON (pos)++;
323 A68G_MON (attr) = CLOSE_SYMBOL;
324 return;
325 } else if (A68G_MON (expr)[A68G_MON (pos)] == '[') {
326 A68G_MON (pos)++;
327 A68G_MON (attr) = SUB_SYMBOL;
328 return;
329 } else if (A68G_MON (expr)[A68G_MON (pos)] == ']') {
330 A68G_MON (pos)++;
331 A68G_MON (attr) = BUS_SYMBOL;
332 return;
333 } else if (A68G_MON (expr)[A68G_MON (pos)] == ',') {
334 A68G_MON (pos)++;
335 A68G_MON (attr) = COMMA_SYMBOL;
336 return;
337 } else if (A68G_MON (expr)[A68G_MON (pos)] == ';') {
338 A68G_MON (pos)++;
339 A68G_MON (attr) = SEMI_SYMBOL;
340 return;
341 }
342 }
343
344
345 //! @brief Find a tag, searching symbol tables towards the root.
346
347 TAG_T *find_tag (TABLE_T * table, int a, char *name)
348 {
349 if (table != NO_TABLE) {
350 TAG_T *s = NO_TAG;
351 if (a == OP_SYMBOL) {
352 s = OPERATORS (table);
353 } else if (a == PRIO_SYMBOL) {
354 s = PRIO (table);
355 } else if (a == IDENTIFIER) {
356 s = IDENTIFIERS (table);
357 } else if (a == INDICANT) {
358 s = INDICANTS (table);
359 } else if (a == LABEL) {
360 s = LABELS (table);
361 } else {
362 ABEND (A68G_TRUE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
363 }
364 for (; s != NO_TAG; FORWARD (s)) {
365 if (strcmp (NSYMBOL (NODE (s)), name) == 0) {
366 return s;
367 }
368 }
369 return find_tag_global (PREVIOUS (table), a, name);
370 } else {
371 return NO_TAG;
372 }
373 }
374
375
376 //! @brief Priority for symbol at input.
377
378 int prio (FILE_T f, NODE_T * p)
379 {
380 (void) p;
381 (void) f;
382 TAG_T *s = find_tag (A68G_STANDENV, PRIO_SYMBOL, A68G_MON (symbol));
383 if (s == NO_TAG) {
384 monitor_error ("unknown operator, cannot set priority", A68G_MON (symbol));
385 return 0;
386 }
387 return PRIO (s);
388 }
389
390
391 //! @brief Push a mode on the stack.
392
393 void push_mode (FILE_T f, MOID_T * m)
394 {
395 (void) f;
396 if (A68G_MON (_m_sp) < MON_STACK_SIZE) {
397 A68G_MON (_m_stack)[A68G_MON (_m_sp)++] = m;
398 } else {
399 monitor_error ("expression too complex", NO_TEXT);
400 }
401 }
402
403
404 //! @brief Dereference, WEAK or otherwise.
405
406 BOOL_T deref_condition (int k, int context)
407 {
408 MOID_T *u = A68G_MON (_m_stack)[k];
409 if (context == WEAK && SUB (u) != NO_MOID) {
410 MOID_T *v = SUB (u);
411 BOOL_T stowed = (BOOL_T) (IS_FLEX (v) || IS_ROW (v) || IS_STRUCT (v));
412 return (BOOL_T) (IS_REF (u) && !stowed);
413 } else {
414 return (BOOL_T) (IS_REF (u));
415 }
416 }
417
418
419 //! @brief Weak dereferencing.
420
421 void deref (NODE_T * p, int k, int context)
422 {
423 while (deref_condition (k, context)) {
424 A68G_REF z;
425 POP_REF (p, &z);
426 CHECK_MON_REF (p, z, A68G_MON (_m_stack)[k]);
427 A68G_MON (_m_stack)[k] = SUB (A68G_MON (_m_stack)[k]);
428 PUSH (p, ADDRESS (&z), SIZE (A68G_MON (_m_stack)[k]));
429 }
430 }
431
432
433 //! @brief Search moid that matches indicant.
434
435 MOID_T *search_mode (int refs, int leng, char *indy)
436 {
437 MOID_T *z = NO_MOID;
438 for (MOID_T *m = TOP_MOID (&A68G_JOB); m != NO_MOID; FORWARD (m)) {
439 if (NODE (m) != NO_NODE) {
440 if (indy == NSYMBOL (NODE (m)) && leng == DIM (m)) {
441 z = m;
442 while (EQUIVALENT (z) != NO_MOID) {
443 z = EQUIVALENT (z);
444 }
445 }
446 }
447 }
448 if (z == NO_MOID) {
449 monitor_error ("unknown indicant", indy);
450 return NO_MOID;
451 }
452 for (MOID_T *m = TOP_MOID (&A68G_JOB); m != NO_MOID; FORWARD (m)) {
453 int k = 0;
454 while (IS_REF (m)) {
455 k++;
456 m = SUB (m);
457 }
458 if (k == refs && m == z) {
459 while (EQUIVALENT (z) != NO_MOID) {
460 z = EQUIVALENT (z);
461 }
462 return z;
463 }
464 }
465 return NO_MOID;
466 }
467
468
469 //! @brief Search operator X SYM Y.
470
471 TAG_T *search_operator (char *sym, MOID_T * x, MOID_T * y)
472 {
473 for (TAG_T *t = OPERATORS (A68G_STANDENV); t != NO_TAG; FORWARD (t)) {
474 if (strcmp (NSYMBOL (NODE (t)), sym) == 0) {
475 PACK_T *p = PACK (MOID (t));
476 if (x == MOID (p)) {
477 FORWARD (p);
478 if (p == NO_PACK && y == NO_MOID) {
479 // Matched in case of a monad.
480 return t;
481 } else if (p != NO_PACK && y != NO_MOID && y == MOID (p)) {
482 // Matched in case of a nomad.
483 return t;
484 }
485 }
486 }
487 }
488 // Not found yet, try dereferencing.
489 if (IS_REF (x)) {
490 return search_operator (sym, SUB (x), y);
491 }
492 if (y != NO_MOID && IS_REF (y)) {
493 return search_operator (sym, x, SUB (y));
494 }
495 // Not found. Grrrr. Give a message.
496 if (y == NO_MOID) {
497 ASSERT (a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s %s", sym, moid_to_string (x, MOID_WIDTH, NO_NODE)) >= 0);
498 } else {
499 ASSERT (a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s %s %s", moid_to_string (x, MOID_WIDTH, NO_NODE), sym, moid_to_string (y, MOID_WIDTH, NO_NODE)) >= 0);
500 }
501 monitor_error ("cannot find operator in standard environ", A68G (edit_line));
502 return NO_TAG;
503 }
504
505
506 //! @brief Search identifier in frame stack and push value.
507
508 void search_identifier (FILE_T f, NODE_T * p, ADDR_T a68g_link, char *sym)
509 {
510 if (a68g_link > 0) {
511 int dynamic_a68g_link = FRAME_DYNAMIC_LINK (a68g_link);
512 if (A68G_MON (current_frame) == 0 || (A68G_MON (current_frame) == FRAME_NUMBER (a68g_link))) {
513 NODE_T *u = FRAME_TREE (a68g_link);
514 if (u != NO_NODE) {
515 TABLE_T *q = TABLE (u);
516 for (TAG_T *i = IDENTIFIERS (q); i != NO_TAG; FORWARD (i)) {
517 if (strcmp (NSYMBOL (NODE (i)), sym) == 0) {
518 ADDR_T posit = a68g_link + FRAME_INFO_SIZE + OFFSET (i);
519 MOID_T *m = MOID (i);
520 PUSH (p, FRAME_ADDRESS (posit), SIZE (m));
521 push_mode (f, m);
522 return;
523 }
524 }
525 }
526 }
527 search_identifier (f, p, dynamic_a68g_link, sym);
528 } else {
529 TABLE_T *q = A68G_STANDENV;
530 for (TAG_T *i = IDENTIFIERS (q); i != NO_TAG; FORWARD (i)) {
531 if (strcmp (NSYMBOL (NODE (i)), sym) == 0) {
532 if (IS (MOID (i), PROC_SYMBOL)) {
533 static A68G_PROCEDURE z;
534 STATUS (&z) = (STATUS_MASK_T) (INIT_MASK | STANDENV_PROC_MASK);
535 PROCEDURE (&(BODY (&z))) = PROCEDURE (i);
536 ENVIRON (&z) = 0;
537 LOCALE (&z) = NO_HANDLE;
538 MOID (&z) = MOID (i);
539 PUSH_PROCEDURE (p, z);
540 } else {
541 NODE_T tmp = *p;
542 MOID (&tmp) = MOID (i); // MP routines consult mode from node.
543 (*(PROCEDURE (i))) (&tmp);
544 }
545 push_mode (f, MOID (i));
546 return;
547 }
548 }
549 monitor_error ("cannot find identifier", sym);
550 }
551 }
552
553
554 //! @brief Coerce arguments in a call.
555
556 void coerce_arguments (FILE_T f, NODE_T * p, MOID_T * proc, int bot, int top, int top_sp)
557 {
558 (void) f;
559 if ((top - bot) != DIM (proc)) {
560 monitor_error ("invalid procedure argument count", NO_TEXT);
561 }
562 QUIT_ON_ERROR;
563 ADDR_T pop_sp = top_sp;
564 PACK_T *u = PACK (proc);
565 for (int k = bot; k < top; k++, FORWARD (u)) {
566 if (A68G_MON (_m_stack)[k] == MOID (u)) {
567 PUSH (p, STACK_ADDRESS (pop_sp), SIZE (MOID (u)));
568 pop_sp += SIZE (MOID (u));
569 } else if (IS_REF (A68G_MON (_m_stack)[k])) {
570 A68G_REF *v = (A68G_REF *) STACK_ADDRESS (pop_sp);
571 PUSH_REF (p, *v);
572 pop_sp += A68G_REF_SIZE;
573 deref (p, k, STRONG);
574 if (A68G_MON (_m_stack)[k] != MOID (u)) {
575 ASSERT (a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s to %s", moid_to_string (A68G_MON (_m_stack)[k], MOID_WIDTH, NO_NODE), moid_to_string (MOID (u), MOID_WIDTH, NO_NODE)) >= 0);
576 monitor_error ("invalid argument mode", A68G (edit_line));
577 }
578 } else {
579 ASSERT (a68g_bufprt (A68G (edit_line), SNPRINTF_SIZE, "%s to %s", moid_to_string (A68G_MON (_m_stack)[k], MOID_WIDTH, NO_NODE), moid_to_string (MOID (u), MOID_WIDTH, NO_NODE)) >= 0);
580 monitor_error ("cannot coerce argument", A68G (edit_line));
581 }
582 QUIT_ON_ERROR;
583 }
584 MOVE (STACK_ADDRESS (top_sp), STACK_ADDRESS (pop_sp), A68G_SP - pop_sp);
585 A68G_SP = top_sp + (A68G_SP - pop_sp);
586 }
587
588
589 //! @brief Perform a selection.
590
591 void selection (FILE_T f, NODE_T * p, char *field)
592 {
593 SCAN_CHECK (f, p);
594 if (A68G_MON (attr) != IDENTIFIER && A68G_MON (attr) != OPEN_SYMBOL) {
595 monitor_error ("invalid selection syntax", NO_TEXT);
596 }
597 QUIT_ON_ERROR;
598 PARSE_CHECK (f, p, MAX_PRIORITY + 1);
599 deref (p, A68G_MON (_m_sp) - 1, WEAK);
600 BOOL_T name; MOID_T *moid; PACK_T *u, *v;
601 if (IS_REF (TOP_MODE)) {
602 name = A68G_TRUE;
603 u = PACK (NAME (TOP_MODE));
604 moid = SUB (A68G_MON (_m_stack)[--A68G_MON (_m_sp)]);
605 v = PACK (moid);
606 } else {
607 name = A68G_FALSE;
608 moid = A68G_MON (_m_stack)[--A68G_MON (_m_sp)];
609 u = PACK (moid);
610 v = PACK (moid);
611 }
612 if (!IS (moid, STRUCT_SYMBOL)) {
613 monitor_error ("invalid selection mode", moid_to_string (moid, MOID_WIDTH, NO_NODE));
614 }
615 QUIT_ON_ERROR;
616 for (; u != NO_PACK; FORWARD (u), FORWARD (v)) {
617 if (strcmp (field, TEXT (u)) == 0) {
618 if (name) {
619 A68G_REF *z = (A68G_REF *) (STACK_OFFSET (-A68G_REF_SIZE));
620 CHECK_MON_REF (p, *z, moid);
621 OFFSET (z) += OFFSET (v);
622 } else {
623 DECREMENT_STACK_POINTER (p, SIZE (moid));
624 MOVE (STACK_TOP, STACK_OFFSET (OFFSET (v)), (UNSIGNED_T) SIZE (MOID (u)));
625 INCREMENT_STACK_POINTER (p, SIZE (MOID (u)));
626 }
627 push_mode (f, MOID (u));
628 return;
629 }
630 }
631 monitor_error ("invalid field name", field);
632 }
633
634
635 //! @brief Perform a call.
636
637 void call (FILE_T f, NODE_T * p, int depth)
638 {
639 (void) depth;
640 QUIT_ON_ERROR;
641 deref (p, A68G_MON (_m_sp) - 1, STRONG);
642 MOID_T *proc = A68G_MON (_m_stack)[--A68G_MON (_m_sp)];
643 if (!IS (proc, PROC_SYMBOL)) {
644 monitor_error ("invalid procedure mode", moid_to_string (proc, MOID_WIDTH, NO_NODE));
645 }
646 QUIT_ON_ERROR;
647 ADDR_T old_m_sp = A68G_MON (_m_sp);
648 A68G_PROCEDURE z;
649 POP_PROCEDURE (p, &z);
650 int args = A68G_MON (_m_sp);
651 ADDR_T top_sp = A68G_SP;
652 if (A68G_MON (attr) == OPEN_SYMBOL) {
653 do {
654 SCAN_CHECK (f, p);
655 PARSE_CHECK (f, p, 0);
656 } while (A68G_MON (attr) == COMMA_SYMBOL);
657 if (A68G_MON (attr) != CLOSE_SYMBOL) {
658 monitor_error ("unmatched parenthesis", NO_TEXT);
659 }
660 SCAN_CHECK (f, p);
661 }
662 coerce_arguments (f, p, proc, args, A68G_MON (_m_sp), top_sp);
663 NODE_T q;
664 if (STATUS (&z) & STANDENV_PROC_MASK) {
665 MOID (&q) = A68G_MON (_m_stack)[--A68G_MON (_m_sp)];
666 INFO (&q) = INFO (p);
667 NSYMBOL (&q) = NSYMBOL (p);
668 (void) ((*PROCEDURE (&(BODY (&z)))) (&q));
669 A68G_MON (_m_sp) = old_m_sp;
670 push_mode (f, SUB_MOID (&z));
671 } else {
672 monitor_error ("can only call standard environ routines", NO_TEXT);
673 }
674 }
675
676
677 //! @brief Perform a slice.
678
679 void slice (FILE_T f, NODE_T * p, int depth)
680 {
681 (void) depth;
682 QUIT_ON_ERROR;
683 deref (p, A68G_MON (_m_sp) - 1, WEAK);
684 BOOL_T name; MOID_T *moid, *res;
685 if (IS_REF (TOP_MODE)) {
686 name = A68G_TRUE;
687 res = NAME (TOP_MODE);
688 deref (p, A68G_MON (_m_sp) - 1, STRONG);
689 moid = A68G_MON (_m_stack)[--A68G_MON (_m_sp)];
690 } else {
691 name = A68G_FALSE;
692 moid = A68G_MON (_m_stack)[--A68G_MON (_m_sp)];
693 res = SUB (moid);
694 }
695 if (!IS_ROW (moid) && !IS_FLEX (moid)) {
696 monitor_error ("invalid row mode", moid_to_string (moid, MOID_WIDTH, NO_NODE));
697 }
698 QUIT_ON_ERROR;
699 // Get descriptor.
700 A68G_REF z;
701 POP_REF (p, &z);
702 CHECK_MON_REF (p, z, moid);
703 A68G_ARRAY *arr; A68G_TUPLE *tup;
704 GET_DESCRIPTOR (arr, tup, &z);
705 int dim;
706 if (IS_FLEX (moid)) {
707 dim = DIM (SUB (moid));
708 } else {
709 dim = DIM (moid);
710 }
711 // Get indexer.
712 int args = A68G_MON (_m_sp);
713 if (A68G_MON (attr) == SUB_SYMBOL) {
714 do {
715 SCAN_CHECK (f, p);
716 PARSE_CHECK (f, p, 0);
717 } while (A68G_MON (attr) == COMMA_SYMBOL);
718 if (A68G_MON (attr) != BUS_SYMBOL) {
719 monitor_error ("unmatched parenthesis", NO_TEXT);
720 }
721 SCAN_CHECK (f, p);
722 }
723 if ((A68G_MON (_m_sp) - args) != dim) {
724 monitor_error ("invalid slice index count", NO_TEXT);
725 }
726 QUIT_ON_ERROR;
727 int index = 0;
728 for (int k = 0; k < dim; k++, A68G_MON (_m_sp)--) {
729 A68G_TUPLE *t = &(tup[dim - k - 1]);
730 deref (p, A68G_MON (_m_sp) - 1, MEEK);
731 if (TOP_MODE != M_INT) {
732 monitor_error ("invalid indexer mode", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
733 }
734 QUIT_ON_ERROR;
735 A68G_INT i;
736 POP_OBJECT (p, &i, A68G_INT);
737 if (VALUE (&i) < LOWER_BOUND (t) || VALUE (&i) > UPPER_BOUND (t)) {
738 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_INDEX_OUT_OF_BOUNDS);
739 exit_genie (p, A68G_RUNTIME_ERROR);
740 }
741 QUIT_ON_ERROR;
742 index += SPAN (t) * VALUE (&i) - SHIFT (t);
743 }
744 ADDR_T address = ROW_ELEMENT (arr, index);
745 if (name) {
746 z = ARRAY (arr);
747 OFFSET (&z) += address;
748 REF_SCOPE (&z) = PRIMAL_SCOPE;
749 PUSH_REF (p, z);
750 } else {
751 PUSH (p, ADDRESS (&(ARRAY (arr))) + address, SIZE (res));
752 }
753 push_mode (f, res);
754 }
755
756
757 //! @brief Perform a call or a slice.
758
759 void call_or_slice (FILE_T f, NODE_T * p, int depth)
760 {
761 while (A68G_MON (attr) == OPEN_SYMBOL || A68G_MON (attr) == SUB_SYMBOL) {
762 QUIT_ON_ERROR;
763 if (A68G_MON (attr) == OPEN_SYMBOL) {
764 call (f, p, depth);
765 } else if (A68G_MON (attr) == SUB_SYMBOL) {
766 slice (f, p, depth);
767 }
768 }
769 }
770
771
772 //! @brief Parse expression on input.
773
774 void parse (FILE_T f, NODE_T * p, int depth)
775 {
776 LOW_STACK_ALERT (p);
777 QUIT_ON_ERROR;
778 if (depth <= MAX_PRIORITY) {
779 if (depth == 0) {
780 // Identity relations.
781 PARSE_CHECK (f, p, 1);
782 while (A68G_MON (attr) == IS_SYMBOL || A68G_MON (attr) == ISNT_SYMBOL) {
783 A68G_REF x, y;
784 BOOL_T res;
785 int op = A68G_MON (attr);
786 if (TOP_MODE != M_HIP && !IS_REF (TOP_MODE)) {
787 monitor_error ("identity relation operand must yield a name", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
788 }
789 SCAN_CHECK (f, p);
790 PARSE_CHECK (f, p, 1);
791 if (TOP_MODE != M_HIP && !IS_REF (TOP_MODE)) {
792 monitor_error ("identity relation operand must yield a name", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
793 }
794 QUIT_ON_ERROR;
795 if (TOP_MODE != M_HIP && A68G_MON (_m_stack)[A68G_MON (_m_sp) - 2] != M_HIP) {
796 if (TOP_MODE != A68G_MON (_m_stack)[A68G_MON (_m_sp) - 2]) {
797 monitor_error ("invalid identity relation operand mode", NO_TEXT);
798 }
799 }
800 QUIT_ON_ERROR;
801 A68G_MON (_m_sp) -= 2;
802 POP_REF (p, &y);
803 POP_REF (p, &x);
804 res = (BOOL_T) (ADDRESS (&x) == ADDRESS (&y));
805 PUSH_VALUE (p, (BOOL_T) (op == IS_SYMBOL ? res : !res), A68G_BOOL);
806 push_mode (f, M_BOOL);
807 }
808 } else {
809 // Dyadic expressions.
810 PARSE_CHECK (f, p, depth + 1);
811 while (A68G_MON (attr) == OPERATOR && prio (f, p) == depth) {
812 BUFFER name;
813 a68g_bufcpy (name, A68G_MON (symbol), BUFFER_SIZE);
814 int args = A68G_MON (_m_sp) - 1;
815 ADDR_T top_sp = A68G_SP - SIZE (A68G_MON (_m_stack)[args]);
816 SCAN_CHECK (f, p);
817 PARSE_CHECK (f, p, depth + 1);
818 TAG_T *opt = search_operator (name, A68G_MON (_m_stack)[A68G_MON (_m_sp) - 2], TOP_MODE);
819 QUIT_ON_ERROR;
820 coerce_arguments (f, p, MOID (opt), args, A68G_MON (_m_sp), top_sp);
821 A68G_MON (_m_sp) -= 2;
822 NODE_T q;
823 MOID (&q) = MOID (opt);
824 INFO (&q) = INFO (p);
825 NSYMBOL (&q) = NSYMBOL (p);
826 (void) ((*(PROCEDURE (opt)))) (&q);
827 push_mode (f, SUB_MOID (opt));
828 }
829 }
830 } else if (A68G_MON (attr) == OPERATOR) {
831 BUFFER name;
832 a68g_bufcpy (name, A68G_MON (symbol), BUFFER_SIZE);
833 int args = A68G_MON (_m_sp);
834 ADDR_T top_sp = A68G_SP;
835 SCAN_CHECK (f, p);
836 PARSE_CHECK (f, p, depth);
837 TAG_T *opt = search_operator (name, TOP_MODE, NO_MOID);
838 QUIT_ON_ERROR;
839 coerce_arguments (f, p, MOID (opt), args, A68G_MON (_m_sp), top_sp);
840 A68G_MON (_m_sp)--;
841 NODE_T q;
842 MOID (&q) = MOID (opt);
843 INFO (&q) = INFO (p);
844 NSYMBOL (&q) = NSYMBOL (p);
845 (void) ((*(PROCEDURE (opt))) (&q));
846 push_mode (f, SUB_MOID (opt));
847 } else if (A68G_MON (attr) == REF_SYMBOL) {
848 int refs = 0, length = 0;
849 MOID_T *m = NO_MOID;
850 while (A68G_MON (attr) == REF_SYMBOL) {
851 refs++;
852 SCAN_CHECK (f, p);
853 }
854 while (A68G_MON (attr) == LONG_SYMBOL) {
855 length++;
856 SCAN_CHECK (f, p);
857 }
858 m = search_mode (refs, length, A68G_MON (symbol));
859 QUIT_ON_ERROR;
860 if (m == NO_MOID) {
861 monitor_error ("unknown reference to mode", NO_TEXT);
862 }
863 SCAN_CHECK (f, p);
864 if (A68G_MON (attr) != OPEN_SYMBOL) {
865 monitor_error ("cast expects open-symbol", NO_TEXT);
866 }
867 SCAN_CHECK (f, p);
868 PARSE_CHECK (f, p, 0);
869 if (A68G_MON (attr) != CLOSE_SYMBOL) {
870 monitor_error ("cast expects close-symbol", NO_TEXT);
871 }
872 SCAN_CHECK (f, p);
873 while (IS_REF (TOP_MODE) && TOP_MODE != m) {
874 MOID_T *sub = SUB (TOP_MODE);
875 A68G_REF z;
876 POP_REF (p, &z);
877 CHECK_MON_REF (p, z, TOP_MODE);
878 PUSH (p, ADDRESS (&z), SIZE (sub));
879 TOP_MODE = sub;
880 }
881 if (TOP_MODE != m) {
882 monitor_error ("invalid cast mode", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
883 }
884 } else if (A68G_MON (attr) == LONG_SYMBOL) {
885 int length = 0;
886 while (A68G_MON (attr) == LONG_SYMBOL) {
887 length++;
888 SCAN_CHECK (f, p);
889 }
890 // Cast L INT -> L REAL.
891 if (A68G_MON (attr) == REAL_SYMBOL) {
892 MOID_T *i = (length == 1 ? M_LONG_INT : M_LONG_LONG_INT);
893 MOID_T *r = (length == 1 ? M_LONG_REAL : M_LONG_LONG_REAL);
894 SCAN_CHECK (f, p);
895 if (A68G_MON (attr) != OPEN_SYMBOL) {
896 monitor_error ("cast expects open-symbol", NO_TEXT);
897 }
898 SCAN_CHECK (f, p);
899 PARSE_CHECK (f, p, 0);
900 if (A68G_MON (attr) != CLOSE_SYMBOL) {
901 monitor_error ("cast expects close-symbol", NO_TEXT);
902 }
903 SCAN_CHECK (f, p);
904 if (TOP_MODE != i) {
905 monitor_error ("invalid cast argument mode", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
906 }
907 QUIT_ON_ERROR;
908 TOP_MODE = r;
909 return;
910 }
911 // L INT or L REAL denotation.
912 MOID_T *m;
913 if (A68G_MON (attr) == INT_DENOTATION) {
914 m = (length == 1 ? M_LONG_INT : M_LONG_LONG_INT);
915 } else if (A68G_MON (attr) == REAL_DENOTATION) {
916 m = (length == 1 ? M_LONG_REAL : M_LONG_LONG_REAL);
917 } else if (A68G_MON (attr) == BITS_DENOTATION) {
918 m = (length == 1 ? M_LONG_BITS : M_LONG_LONG_BITS);
919 } else {
920 m = NO_MOID;
921 }
922 if (m != NO_MOID) {
923 int digits = DIGITS (m);
924 MP_T *z = nil_mp (p, digits);
925 if (genie_string_to_value_internal (p, m, A68G_MON (symbol), (BYTE_T *) z) == A68G_FALSE) {
926 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, m);
927 exit_genie (p, A68G_RUNTIME_ERROR);
928 }
929 MP_STATUS (z) = (MP_T) ((UNSIGNED_T) MP_STATUS (z) | INIT_MASK | CONSTANT_MASK);
930 push_mode (f, m);
931 SCAN_CHECK (f, p);
932 } else {
933 monitor_error ("invalid mode", NO_TEXT);
934 }
935 } else if (A68G_MON (attr) == INT_DENOTATION) {
936 A68G_INT z;
937 if (genie_string_to_value_internal (p, M_INT, A68G_MON (symbol), (BYTE_T *) & z) == A68G_FALSE) {
938 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, M_INT);
939 exit_genie (p, A68G_RUNTIME_ERROR);
940 }
941 PUSH_VALUE (p, VALUE (&z), A68G_INT);
942 push_mode (f, M_INT);
943 SCAN_CHECK (f, p);
944 } else if (A68G_MON (attr) == REAL_DENOTATION) {
945 A68G_REAL z;
946 if (genie_string_to_value_internal (p, M_REAL, A68G_MON (symbol), (BYTE_T *) & z) == A68G_FALSE) {
947 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, M_REAL);
948 exit_genie (p, A68G_RUNTIME_ERROR);
949 }
950 PUSH_VALUE (p, VALUE (&z), A68G_REAL);
951 push_mode (f, M_REAL);
952 SCAN_CHECK (f, p);
953 } else if (A68G_MON (attr) == BITS_DENOTATION) {
954 A68G_BITS z;
955 if (genie_string_to_value_internal (p, M_BITS, A68G_MON (symbol), (BYTE_T *) & z) == A68G_FALSE) {
956 diagnostic (A68G_RUNTIME_ERROR, p, ERROR_IN_DENOTATION, M_BITS);
957 exit_genie (p, A68G_RUNTIME_ERROR);
958 }
959 PUSH_VALUE (p, VALUE (&z), A68G_BITS);
960 push_mode (f, M_BITS);
961 SCAN_CHECK (f, p);
962 } else if (A68G_MON (attr) == ROW_CHAR_DENOTATION) {
963 if (strlen (A68G_MON (symbol)) == 1) {
964 PUSH_VALUE (p, A68G_MON (symbol)[0], A68G_CHAR);
965 push_mode (f, M_CHAR);
966 } else {
967 A68G_REF z = c_to_a_string (p, A68G_MON (symbol), DEFAULT_WIDTH);
968 A68G_ARRAY *arr; A68G_TUPLE *tup;
969 GET_DESCRIPTOR (arr, tup, &z);
970 BLOCK_GC_HANDLE (&z);
971 BLOCK_GC_HANDLE (&(ARRAY (arr)));
972 PUSH_REF (p, z);
973 push_mode (f, M_STRING);
974 (void) tup;
975 }
976 SCAN_CHECK (f, p);
977 } else if (A68G_MON (attr) == TRUE_SYMBOL) {
978 PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
979 push_mode (f, M_BOOL);
980 SCAN_CHECK (f, p);
981 } else if (A68G_MON (attr) == FALSE_SYMBOL) {
982 PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
983 push_mode (f, M_BOOL);
984 SCAN_CHECK (f, p);
985 } else if (A68G_MON (attr) == NIL_SYMBOL) {
986 PUSH_REF (p, nil_ref);
987 push_mode (f, M_HIP);
988 SCAN_CHECK (f, p);
989 } else if (A68G_MON (attr) == REAL_SYMBOL) {
990 SCAN_CHECK (f, p);
991 if (A68G_MON (attr) != OPEN_SYMBOL) {
992 monitor_error ("cast expects open-symbol", NO_TEXT);
993 }
994 SCAN_CHECK (f, p);
995 PARSE_CHECK (f, p, 0);
996 if (A68G_MON (attr) != CLOSE_SYMBOL) {
997 monitor_error ("cast expects close-symbol", NO_TEXT);
998 }
999 SCAN_CHECK (f, p);
1000 if (TOP_MODE != M_INT) {
1001 monitor_error ("invalid cast argument mode", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
1002 }
1003 QUIT_ON_ERROR;
1004 A68G_INT k;
1005 POP_OBJECT (p, &k, A68G_INT);
1006 PUSH_VALUE (p, (REAL_T) VALUE (&k), A68G_REAL);
1007 TOP_MODE = M_REAL;
1008 } else if (A68G_MON (attr) == IDENTIFIER) {
1009 ADDR_T old_sp = A68G_SP;
1010 BUFFER name;
1011 a68g_bufcpy (name, A68G_MON (symbol), BUFFER_SIZE);
1012 SCAN_CHECK (f, p);
1013 if (A68G_MON (attr) == OF_SYMBOL) {
1014 selection (f, p, name);
1015 } else {
1016 search_identifier (f, p, A68G_FP, name);
1017 QUIT_ON_ERROR;
1018 call_or_slice (f, p, depth);
1019 }
1020 QUIT_ON_ERROR;
1021 MOID_T *moid = TOP_MODE;
1022 BOOL_T init;
1023 if (check_initialisation (p, STACK_ADDRESS (old_sp), moid, &init)) {
1024 if (init == A68G_FALSE) {
1025 monitor_error (NO_VALUE, name);
1026 }
1027 } else {
1028 monitor_error ("cannot process value of mode", moid_to_string (moid, MOID_WIDTH, NO_NODE));
1029 }
1030 } else if (A68G_MON (attr) == OPEN_SYMBOL) {
1031 do {
1032 SCAN_CHECK (f, p);
1033 PARSE_CHECK (f, p, 0);
1034 } while (A68G_MON (attr) == COMMA_SYMBOL);
1035 if (A68G_MON (attr) != CLOSE_SYMBOL) {
1036 monitor_error ("unmatched parenthesis", NO_TEXT);
1037 }
1038 SCAN_CHECK (f, p);
1039 call_or_slice (f, p, depth);
1040 } else {
1041 monitor_error ("invalid expression syntax", NO_TEXT);
1042 }
1043 }
1044
1045
1046 //! @brief Perform assignment.
1047
1048 void assign (FILE_T f, NODE_T * p)
1049 {
1050 LOW_STACK_ALERT (p);
1051 PARSE_CHECK (f, p, 0);
1052 if (A68G_MON (attr) == ASSIGN_SYMBOL) {
1053 MOID_T *m = A68G_MON (_m_stack)[--A68G_MON (_m_sp)];
1054 A68G_REF z;
1055 if (!IS_REF (m)) {
1056 monitor_error ("invalid destination mode", moid_to_string (m, MOID_WIDTH, NO_NODE));
1057 }
1058 QUIT_ON_ERROR;
1059 POP_REF (p, &z);
1060 CHECK_MON_REF (p, z, m);
1061 SCAN_CHECK (f, p);
1062 assign (f, p);
1063 QUIT_ON_ERROR;
1064 while (IS_REF (TOP_MODE) && TOP_MODE != SUB (m)) {
1065 MOID_T *sub = SUB (TOP_MODE);
1066 A68G_REF y;
1067 POP_REF (p, &y);
1068 CHECK_MON_REF (p, y, TOP_MODE);
1069 PUSH (p, ADDRESS (&y), SIZE (sub));
1070 TOP_MODE = sub;
1071 }
1072 if (TOP_MODE != SUB (m) && TOP_MODE != M_HIP) {
1073 monitor_error ("invalid source mode", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
1074 }
1075 QUIT_ON_ERROR;
1076 POP (p, ADDRESS (&z), SIZE (TOP_MODE));
1077 PUSH_REF (p, z);
1078 TOP_MODE = m;
1079 }
1080 }
1081
1082
1083 //! @brief Evaluate expression on input.
1084
1085 void evaluate (FILE_T f, NODE_T * p, char *str)
1086 {
1087 LOW_STACK_ALERT (p);
1088 A68G_MON (_m_sp) = 0;
1089 A68G_MON (_m_stack)[0] = NO_MOID;
1090 A68G_MON (pos) = 0;
1091 a68g_bufcpy (A68G_MON (expr), str, BUFFER_SIZE);
1092 SCAN_CHECK (f, p);
1093 QUIT_ON_ERROR;
1094 assign (f, p);
1095 if (A68G_MON (attr) != 0) {
1096 monitor_error ("trailing character in expression", A68G_MON (symbol));
1097 }
1098 }
1099
1100
1101 //! @brief Convert string to int.
1102
1103 int get_num_arg (char *num, char **rest)
1104 {
1105 if (rest != NO_REF) {
1106 *rest = NO_TEXT;
1107 }
1108 if (num == NO_TEXT) {
1109 return NOT_A_NUM;
1110 }
1111 SKIP_ONE_SYMBOL (num);
1112 if (IS_DIGIT (num[0])) {
1113 errno = 0;
1114 char *end;
1115 int k = (int) a68g_strtou (num, &end, 10);
1116 if (end != num && errno == 0) {
1117 if (rest != NO_REF) {
1118 *rest = end;
1119 }
1120 return k;
1121 } else {
1122 monitor_error ("invalid numerical argument", error_specification ());
1123 return NOT_A_NUM;
1124 }
1125 } else {
1126 if (num[0] != NULL_CHAR) {
1127 monitor_error ("invalid numerical argument", num);
1128 }
1129 return NOT_A_NUM;
1130 }
1131 }
1132
1133
1134 //! @brief Whether item at "w" of mode "q" is initialised.
1135
1136 BOOL_T check_initialisation (NODE_T * p, BYTE_T * w, MOID_T * q, BOOL_T * result)
1137 {
1138 BOOL_T initialised = A68G_FALSE, recognised = A68G_FALSE;
1139 (void) p;
1140 switch (SHORT_ID (q)) {
1141 case MODE_NO_CHECK:
1142 case UNION_SYMBOL: {
1143 initialised = A68G_TRUE;
1144 recognised = A68G_TRUE;
1145 break;
1146 }
1147 case REF_SYMBOL: {
1148 A68G_REF *z = (A68G_REF *) w;
1149 initialised = INITIALISED (z);
1150 recognised = A68G_TRUE;
1151 break;
1152 }
1153 case PROC_SYMBOL: {
1154 A68G_PROCEDURE *z = (A68G_PROCEDURE *) w;
1155 initialised = INITIALISED (z);
1156 recognised = A68G_TRUE;
1157 break;
1158 }
1159 case MODE_INT: {
1160 A68G_INT *z = (A68G_INT *) w;
1161 initialised = INITIALISED (z);
1162 recognised = A68G_TRUE;
1163 break;
1164 }
1165 case MODE_REAL: {
1166 A68G_REAL *z = (A68G_REAL *) w;
1167 initialised = INITIALISED (z);
1168 recognised = A68G_TRUE;
1169 break;
1170 }
1171 case MODE_COMPLEX: {
1172 A68G_REAL *r = (A68G_REAL *) w;
1173 A68G_REAL *i = (A68G_REAL *) (w + SIZE_ALIGNED (A68G_REAL));
1174 initialised = (BOOL_T) (INITIALISED (r) && INITIALISED (i));
1175 recognised = A68G_TRUE;
1176 break;
1177 }
1178 case MODE_LONG_LONG_INT:
1179 case MODE_LONG_LONG_REAL:
1180 case MODE_LONG_LONG_BITS: {
1181 MP_T *z = (MP_T *) w;
1182 initialised = (BOOL_T) ((UNSIGNED_T) MP_STATUS (z) & INIT_MASK);
1183 recognised = A68G_TRUE;
1184 break;
1185 }
1186 case MODE_LONG_COMPLEX: {
1187 MP_T *r = (MP_T *) w;
1188 MP_T *i = (MP_T *) (w + size_mp ());
1189 initialised = (BOOL_T) (((UNSIGNED_T) MP_STATUS (r) & INIT_MASK) && ((UNSIGNED_T) MP_STATUS (i) & INIT_MASK));
1190 recognised = A68G_TRUE;
1191 break;
1192 }
1193 case MODE_LONG_LONG_COMPLEX: {
1194 MP_T *r = (MP_T *) w;
1195 MP_T *i = (MP_T *) (w + size_mp ());
1196 initialised = (BOOL_T) (((UNSIGNED_T) MP_STATUS (r) & INIT_MASK) && ((UNSIGNED_T) MP_STATUS (i) & INIT_MASK));
1197 recognised = A68G_TRUE;
1198 break;
1199 }
1200 case MODE_BOOL: {
1201 A68G_BOOL *z = (A68G_BOOL *) w;
1202 initialised = INITIALISED (z);
1203 recognised = A68G_TRUE;
1204 break;
1205 }
1206 case MODE_CHAR: {
1207 A68G_CHAR *z = (A68G_CHAR *) w;
1208 initialised = INITIALISED (z);
1209 recognised = A68G_TRUE;
1210 break;
1211 }
1212 case MODE_BITS: {
1213 A68G_BITS *z = (A68G_BITS *) w;
1214 initialised = INITIALISED (z);
1215 recognised = A68G_TRUE;
1216 break;
1217 }
1218 case MODE_BYTES: {
1219 A68G_BYTES *z = (A68G_BYTES *) w;
1220 initialised = INITIALISED (z);
1221 recognised = A68G_TRUE;
1222 break;
1223 }
1224 case MODE_LONG_BYTES: {
1225 A68G_LONG_BYTES *z = (A68G_LONG_BYTES *) w;
1226 initialised = INITIALISED (z);
1227 recognised = A68G_TRUE;
1228 break;
1229 }
1230 case MODE_FILE: {
1231 A68G_FILE *z = (A68G_FILE *) w;
1232 initialised = INITIALISED (z);
1233 recognised = A68G_TRUE;
1234 break;
1235 }
1236 case MODE_FORMAT: {
1237 A68G_FORMAT *z = (A68G_FORMAT *) w;
1238 initialised = INITIALISED (z);
1239 recognised = A68G_TRUE;
1240 break;
1241 }
1242 case MODE_PIPE: {
1243 A68G_REF *pipe_read = (A68G_REF *) w;
1244 A68G_REF *pipe_write = (A68G_REF *) (w + A68G_REF_SIZE);
1245 A68G_INT *pid = (A68G_INT *) (w + 2 * A68G_REF_SIZE);
1246 initialised = (BOOL_T) (INITIALISED (pipe_read) && INITIALISED (pipe_write) && INITIALISED (pid));
1247 recognised = A68G_TRUE;
1248 break;
1249 }
1250 case MODE_SOUND: {
1251 A68G_SOUND *z = (A68G_SOUND *) w;
1252 initialised = INITIALISED (z);
1253 recognised = A68G_TRUE;
1254 }
1255 #if (A68G_LEVEL >= 3)
1256 case MODE_LONG_INT:
1257 case MODE_LONG_BITS: {
1258 A68G_LONG_INT *z = (A68G_LONG_INT *) w;
1259 initialised = INITIALISED (z);
1260 recognised = A68G_TRUE;
1261 break;
1262 }
1263 case MODE_LONG_REAL: {
1264 A68G_LONG_REAL *z = (A68G_LONG_REAL *) w;
1265 initialised = INITIALISED (z);
1266 recognised = A68G_TRUE;
1267 break;
1268 }
1269 #else
1270 case MODE_LONG_INT:
1271 case MODE_LONG_REAL:
1272 case MODE_LONG_BITS: {
1273 MP_T *z = (MP_T *) w;
1274 initialised = (BOOL_T) ((UNSIGNED_T) MP_STATUS (z) & INIT_MASK);
1275 recognised = A68G_TRUE;
1276 break;
1277 }
1278 #endif
1279 }
1280 if (result != NO_BOOL) {
1281 *result = initialised;
1282 }
1283 return recognised;
1284 }
1285
1286
1287 //! @brief Show value of object.
1288
1289 void print_item (NODE_T * p, FILE_T f, BYTE_T * item, MOID_T * mode)
1290 {
1291 A68G_REF nil_file = nil_ref;
1292 reset_transput_buffer (UNFORMATTED_BUFFER);
1293 genie_write_standard (p, mode, item, nil_file);
1294 if (get_transput_buffer_index (UNFORMATTED_BUFFER) > 0) {
1295 if (mode == M_CHAR || mode == M_ROW_CHAR || mode == M_STRING) {
1296 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " \"%s\"", get_transput_buffer (UNFORMATTED_BUFFER)) >= 0);
1297 WRITE (f, A68G (output_line));
1298 } else {
1299 char *str = get_transput_buffer (UNFORMATTED_BUFFER);
1300 while (IS_SPACE (str[0])) {
1301 str++;
1302 }
1303 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " %s", str) >= 0);
1304 WRITE (f, A68G (output_line));
1305 }
1306 } else {
1307 WRITE (f, CANNOT_SHOW);
1308 }
1309 }
1310
1311
1312 //! @brief Indented indent_crlf.
1313
1314 void indent_crlf (FILE_T f)
1315 {
1316 if (f == A68G_STDOUT) {
1317 io_close_tty_line ();
1318 }
1319 for (int k = 0; k < A68G_MON (tabs); k++) {
1320 WRITE (f, " ");
1321 }
1322 }
1323
1324
1325 //! @brief Show value of object.
1326
1327 void show_item (FILE_T f, NODE_T * p, BYTE_T * item, MOID_T * mode)
1328 {
1329 if (item == NO_BYTE || mode == NO_MOID) {
1330 return;
1331 }
1332 if (IS_REF (mode)) {
1333 A68G_REF *z = (A68G_REF *) item;
1334 if (IS_NIL (*z)) {
1335 if (INITIALISED (z)) {
1336 WRITE (A68G_STDOUT, " = NIL");
1337 } else {
1338 WRITE (A68G_STDOUT, NO_VALUE);
1339 }
1340 } else {
1341 if (INITIALISED (z)) {
1342 WRITE (A68G_STDOUT, " refers to ");
1343 if (IS_IN_HEAP (z)) {
1344 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "heap(%p)", (void *) ADDRESS (z)) >= 0);
1345 WRITE (A68G_STDOUT, A68G (output_line));
1346 A68G_MON (tabs)++;
1347 show_item (f, p, ADDRESS (z), SUB (mode));
1348 A68G_MON (tabs)--;
1349 } else if (IS_IN_FRAME (z)) {
1350 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "frame(" A68G_LU ")", REF_OFFSET (z)) >= 0);
1351 WRITE (A68G_STDOUT, A68G (output_line));
1352 } else if (IS_IN_STACK (z)) {
1353 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "stack(" A68G_LU ")", REF_OFFSET (z)) >= 0);
1354 WRITE (A68G_STDOUT, A68G (output_line));
1355 }
1356 } else {
1357 WRITE (A68G_STDOUT, NO_VALUE);
1358 }
1359 }
1360 } else if (mode == M_STRING) {
1361 if (!INITIALISED ((A68G_REF *) item)) {
1362 WRITE (A68G_STDOUT, NO_VALUE);
1363 } else {
1364 print_item (p, f, item, mode);
1365 }
1366 } else if ((IS_ROW (mode) || IS_FLEX (mode)) && mode != M_STRING) {
1367 MOID_T *deflexed = DEFLEX (mode);
1368 int old_tabs = A68G_MON (tabs);
1369 A68G_MON (tabs) += 2;
1370 if (!INITIALISED ((A68G_REF *) item)) {
1371 WRITE (A68G_STDOUT, NO_VALUE);
1372 } else {
1373 A68G_ARRAY *arr; A68G_TUPLE *tup;
1374 GET_DESCRIPTOR (arr, tup, (A68G_REF *) item);
1375 size_t elems = get_row_size (tup, DIM (arr));
1376 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, ", %d element(s)", elems) >= 0);
1377 WRITE (f, A68G (output_line));
1378 if (get_row_size (tup, DIM (arr)) != 0) {
1379 BYTE_T *base_addr = ADDRESS (&ARRAY (arr));
1380 BOOL_T done = A68G_FALSE;
1381 initialise_internal_index (tup, DIM (arr));
1382 int count = 0, act_count = 0;
1383 while (!done && ++count <= (A68G_MON (max_row_elems) + 1)) {
1384 if (count <= A68G_MON (max_row_elems)) {
1385 ADDR_T row_index = calculate_internal_index (tup, DIM (arr));
1386 ADDR_T elem_addr = ROW_ELEMENT (arr, row_index);
1387 BYTE_T *elem = &base_addr[elem_addr];
1388 indent_crlf (f);
1389 WRITE (f, "[");
1390 print_internal_index (f, tup, DIM (arr));
1391 WRITE (f, "]");
1392 show_item (f, p, elem, SUB (deflexed));
1393 act_count++;
1394 done = increment_internal_index (tup, DIM (arr));
1395 }
1396 }
1397 indent_crlf (f);
1398 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " %d element(s) written (%d%%)", act_count, (int) ((100.0 * act_count) / elems)) >= 0);
1399 WRITE (f, A68G (output_line));
1400 }
1401 }
1402 A68G_MON (tabs) = old_tabs;
1403 } else if (IS_STRUCT (mode)) {
1404 A68G_MON (tabs)++;
1405 for (PACK_T *q = PACK (mode); q != NO_PACK; FORWARD (q)) {
1406 BYTE_T *elem = &item[OFFSET (q)];
1407 indent_crlf (f);
1408 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " %s \"%s\"", moid_to_string (MOID (q), MOID_WIDTH, NO_NODE), TEXT (q)) >= 0);
1409 WRITE (A68G_STDOUT, A68G (output_line));
1410 show_item (f, p, elem, MOID (q));
1411 }
1412 A68G_MON (tabs)--;
1413 } else if (IS (mode, UNION_SYMBOL)) {
1414 A68G_UNION *z = (A68G_UNION *) item;
1415 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " united-moid %s", moid_to_string ((MOID_T *) (VALUE (z)), MOID_WIDTH, NO_NODE)) >= 0);
1416 WRITE (A68G_STDOUT, A68G (output_line));
1417 show_item (f, p, &item[SIZE_ALIGNED (A68G_UNION)], (MOID_T *) (VALUE (z)));
1418 } else if (mode == M_SIMPLIN) {
1419 A68G_UNION *z = (A68G_UNION *) item;
1420 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " united-moid %s", moid_to_string ((MOID_T *) (VALUE (z)), MOID_WIDTH, NO_NODE)) >= 0);
1421 WRITE (A68G_STDOUT, A68G (output_line));
1422 } else if (mode == M_SIMPLOUT) {
1423 A68G_UNION *z = (A68G_UNION *) item;
1424 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " united-moid %s", moid_to_string ((MOID_T *) (VALUE (z)), MOID_WIDTH, NO_NODE)) >= 0);
1425 WRITE (A68G_STDOUT, A68G (output_line));
1426 } else {
1427 BOOL_T init;
1428 if (check_initialisation (p, item, mode, &init)) {
1429 if (init) {
1430 if (IS (mode, PROC_SYMBOL)) {
1431 A68G_PROCEDURE *z = (A68G_PROCEDURE *) item;
1432 if (z != NO_PROCEDURE && STATUS (z) & STANDENV_PROC_MASK) {
1433 char *fname = standard_environ_proc_name (*(PROCEDURE (&BODY (z))));
1434 WRITE (A68G_STDOUT, " standenv procedure");
1435 if (fname != NO_TEXT) {
1436 WRITE (A68G_STDOUT, " (");
1437 WRITE (A68G_STDOUT, fname);
1438 WRITE (A68G_STDOUT, ")");
1439 }
1440 } else if (z != NO_PROCEDURE && STATUS (z) & SKIP_PROCEDURE_MASK) {
1441 WRITE (A68G_STDOUT, " skip procedure");
1442 } else if (z != NO_PROCEDURE && (PROCEDURE (&BODY (z))) != NO_GPROC) {
1443 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " line %d, environ at frame(" A68G_LU "), locale %p", LINE_NUMBER ((NODE_T *) NODE (&BODY (z))), ENVIRON (z), (void *) LOCALE (z)) >= 0);
1444 WRITE (A68G_STDOUT, A68G (output_line));
1445 } else {
1446 WRITE (A68G_STDOUT, " cannot show value");
1447 }
1448 } else if (mode == M_FORMAT) {
1449 A68G_FORMAT *z = (A68G_FORMAT *) item;
1450 if (z != NO_FORMAT && BODY (z) != NO_NODE) {
1451 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " line %d, environ at frame(" A68G_LU ")", LINE_NUMBER (BODY (z)), ENVIRON (z)) >= 0);
1452 WRITE (A68G_STDOUT, A68G (output_line));
1453 } else {
1454 monitor_error (CANNOT_SHOW, NO_TEXT);
1455 }
1456 } else if (mode == M_SOUND) {
1457 A68G_SOUND *z = (A68G_SOUND *) item;
1458 if (z != NO_SOUND) {
1459 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "%u channels, %u bits, %u rate, %u samples", NUM_CHANNELS (z), BITS_PER_SAMPLE (z), SAMPLE_RATE (z), NUM_SAMPLES (z)) >= 0);
1460 WRITE (A68G_STDOUT, A68G (output_line));
1461
1462 } else {
1463 monitor_error (CANNOT_SHOW, NO_TEXT);
1464 }
1465 } else {
1466 print_item (p, f, item, mode);
1467 }
1468 } else {
1469 WRITE (A68G_STDOUT, NO_VALUE);
1470 }
1471 } else {
1472 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " mode %s, %s", moid_to_string (mode, MOID_WIDTH, NO_NODE), CANNOT_SHOW) >= 0);
1473 WRITE (A68G_STDOUT, A68G (output_line));
1474 }
1475 }
1476 }
1477
1478
1479 //! @brief Overview of frame item.
1480
1481 void show_frame_item (FILE_T f, NODE_T * p, ADDR_T a68g_link, TAG_T * q, int modif)
1482 {
1483 (void) p;
1484 ADDR_T addr = a68g_link + FRAME_INFO_SIZE + OFFSET (q);
1485 ADDR_T loc = FRAME_INFO_SIZE + OFFSET (q);
1486 indent_crlf (A68G_STDOUT);
1487 if (modif != ANONYMOUS) {
1488 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " frame(" A68G_LU "=" A68G_LU "+" A68G_LU ") %s \"%s\"", addr, a68g_link, loc, moid_to_string (MOID (q), MOID_WIDTH, NO_NODE), NSYMBOL (NODE (q))) >= 0);
1489 WRITE (A68G_STDOUT, A68G (output_line));
1490 show_item (f, p, FRAME_ADDRESS (addr), MOID (q));
1491 } else {
1492 switch (PRIO (q)) {
1493 case GENERATOR: {
1494 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " frame(" A68G_LU "=" A68G_LU "+" A68G_LU ") LOC %s", addr, a68g_link, loc, moid_to_string (MOID (q), MOID_WIDTH, NO_NODE)) >= 0);
1495 WRITE (A68G_STDOUT, A68G (output_line));
1496 break;
1497 }
1498 default: {
1499 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, " frame(" A68G_LU "=" A68G_LU "+" A68G_LU ") internal %s", addr, a68g_link, loc, moid_to_string (MOID (q), MOID_WIDTH, NO_NODE)) >= 0);
1500 WRITE (A68G_STDOUT, A68G (output_line));
1501 break;
1502 }
1503 }
1504 show_item (f, p, FRAME_ADDRESS (addr), MOID (q));
1505 }
1506 }
1507
1508
1509 //! @brief Overview of frame items.
1510
1511 void show_frame_items (FILE_T f, NODE_T * p, ADDR_T a68g_link, TAG_T * q, int modif)
1512 {
1513 (void) p;
1514 for (; q != NO_TAG; FORWARD (q)) {
1515 show_frame_item (f, p, a68g_link, q, modif);
1516 }
1517 }
1518
1519
1520 //! @brief Introduce stack frame.
1521
1522 void intro_frame (FILE_T f, NODE_T * p, ADDR_T a68g_link, int *printed)
1523 {
1524 if (*printed > 0) {
1525 WRITELN (f, "");
1526 }
1527 (*printed)++;
1528 TABLE_T *q = TABLE (p);
1529 where_in_source (f, p);
1530 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Stack frame %d at frame(" A68G_LU "), level=%d, size=" A68G_LU " bytes", FRAME_NUMBER (a68g_link), a68g_link, LEVEL (q), (UNSIGNED_T) (FRAME_INCREMENT (a68g_link) + FRAME_INFO_SIZE)) >= 0);
1531 WRITELN (f, A68G (output_line));
1532 }
1533
1534
1535 //! @brief View contents of stack frame.
1536
1537 void show_stack_frame (FILE_T f, NODE_T * p, ADDR_T a68g_link, int *printed)
1538 {
1539 // show the frame starting at frame pointer 'a68g_link', using symbol table from p as a map.
1540 if (p != NO_NODE) {
1541 TABLE_T *q = TABLE (p);
1542 intro_frame (f, p, a68g_link, printed);
1543 #if (A68G_LEVEL >= 3)
1544 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Dynamic link=frame(%llu), static link=frame(%llu), parameters=frame(%llu)", FRAME_DYNAMIC_LINK (a68g_link), FRAME_STATIC_LINK (a68g_link), FRAME_PARAMETERS (a68g_link)) >= 0);
1545 WRITELN (A68G_STDOUT, A68G (output_line));
1546 #else
1547 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Dynamic link=frame(%u), static link=frame(%u), parameters=frame(%u)", FRAME_DYNAMIC_LINK (a68g_link), FRAME_STATIC_LINK (a68g_link), FRAME_PARAMETERS (a68g_link)) >= 0);
1548 WRITELN (A68G_STDOUT, A68G (output_line));
1549 #endif
1550 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Procedure frame=%s", (FRAME_PROC_FRAME (a68g_link) ? "yes" : "no")) >= 0);
1551 WRITELN (A68G_STDOUT, A68G (output_line));
1552 #if defined (BUILD_PARALLEL_CLAUSE)
1553 if (pthread_equal (FRAME_THREAD_ID (a68g_link), A68G_PAR (main_thread_id)) != 0) {
1554 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "In main thread") >= 0);
1555 } else {
1556 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Not in main thread") >= 0);
1557 }
1558 WRITELN (A68G_STDOUT, A68G (output_line));
1559 #endif
1560 show_frame_items (f, p, a68g_link, IDENTIFIERS (q), IDENTIFIER);
1561 show_frame_items (f, p, a68g_link, OPERATORS (q), OPERATOR);
1562 show_frame_items (f, p, a68g_link, ANONYMOUS (q), ANONYMOUS);
1563 }
1564 }
1565
1566
1567 //! @brief Shows lines around the line where 'p' is at.
1568
1569 void list (FILE_T f, NODE_T * p, int n, int m)
1570 {
1571 if (p != NO_NODE) {
1572 if (m == 0) {
1573 LINE_T *r = LINE (INFO (p));
1574 for (LINE_T *l = TOP_LINE (&A68G_JOB); l != NO_LINE; FORWARD (l)) {
1575 if (NUMBER (l) > 0 && abs (NUMBER (r) - NUMBER (l)) <= n) {
1576 write_source_line (f, l, NO_NODE, A68G_TRUE);
1577 }
1578 }
1579 } else {
1580 for (LINE_T *l = TOP_LINE (&A68G_JOB); l != NO_LINE; FORWARD (l)) {
1581 if (NUMBER (l) > 0 && NUMBER (l) >= n && NUMBER (l) <= m) {
1582 write_source_line (f, l, NO_NODE, A68G_TRUE);
1583 }
1584 }
1585 }
1586 }
1587 }
1588
1589
1590 //! @brief Overview of the heap.
1591
1592 void show_heap (FILE_T f, NODE_T * p, A68G_HANDLE * z, int top, int n)
1593 {
1594 int k = 0, m = n, sum = 0;
1595 (void) p;
1596 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "size=%u available=%d garbage collections=" A68G_LD, A68G (heap_size), heap_available (), A68G_GC (sweeps)) >= 0);
1597 WRITELN (f, A68G (output_line));
1598 for (; z != NO_HANDLE; FORWARD (z), k++) {
1599 if (n > 0 && sum <= top) {
1600 n--;
1601 indent_crlf (f);
1602 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "heap(%p+%d) %s", (void *) POINTER (z), SIZE (z), moid_to_string (MOID (z), MOID_WIDTH, NO_NODE)) >= 0);
1603 WRITE (f, A68G (output_line));
1604 sum += SIZE (z);
1605 }
1606 }
1607 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "printed %d out of %d handles", m, k) >= 0);
1608 WRITELN (f, A68G (output_line));
1609 }
1610
1611
1612 //! @brief Search current frame and print it.
1613
1614 void stack_dump_current (FILE_T f, ADDR_T a68g_link)
1615 {
1616 if (a68g_link > 0) {
1617 int dynamic_a68g_link = FRAME_DYNAMIC_LINK (a68g_link);
1618 NODE_T *p = FRAME_TREE (a68g_link);
1619 if (p != NO_NODE && LEVEL (TABLE (p)) > 3) {
1620 if (FRAME_NUMBER (a68g_link) == A68G_MON (current_frame)) {
1621 int printed = 0;
1622 show_stack_frame (f, p, a68g_link, &printed);
1623 } else {
1624 stack_dump_current (f, dynamic_a68g_link);
1625 }
1626 }
1627 }
1628 }
1629
1630
1631 //! @brief Overview of the stack.
1632
1633 void stack_a68g_link_dump (FILE_T f, ADDR_T a68g_link, int depth, int *printed)
1634 {
1635 if (depth > 0 && a68g_link > 0) {
1636 NODE_T *p = FRAME_TREE (a68g_link);
1637 if (p != NO_NODE && LEVEL (TABLE (p)) > 3) {
1638 show_stack_frame (f, p, a68g_link, printed);
1639 stack_a68g_link_dump (f, FRAME_STATIC_LINK (a68g_link), depth - 1, printed);
1640 }
1641 }
1642 }
1643
1644
1645 //! @brief Overview of the stack.
1646
1647 void stack_dump (FILE_T f, ADDR_T a68g_link, int depth, int *printed)
1648 {
1649 if (depth > 0 && a68g_link > 0) {
1650 NODE_T *p = FRAME_TREE (a68g_link);
1651 if (p != NO_NODE && LEVEL (TABLE (p)) > 3) {
1652 show_stack_frame (f, p, a68g_link, printed);
1653 stack_dump (f, FRAME_DYNAMIC_LINK (a68g_link), depth - 1, printed);
1654 }
1655 }
1656 }
1657
1658
1659 //! @brief Overview of the stack.
1660
1661 void stack_trace (FILE_T f, ADDR_T a68g_link, int depth, int *printed)
1662 {
1663 if (depth > 0 && a68g_link > 0) {
1664 int dynamic_a68g_link = FRAME_DYNAMIC_LINK (a68g_link);
1665 if (FRAME_PROC_FRAME (a68g_link)) {
1666 NODE_T *p = FRAME_TREE (a68g_link);
1667 show_stack_frame (f, p, a68g_link, printed);
1668 stack_trace (f, dynamic_a68g_link, depth - 1, printed);
1669 } else {
1670 stack_trace (f, dynamic_a68g_link, depth, printed);
1671 }
1672 }
1673 }
1674
1675
1676 //! @brief Examine tags.
1677
1678 void examine_tags (FILE_T f, NODE_T * p, ADDR_T a68g_link, TAG_T * q, char *sym, int *printed)
1679 {
1680 for (; q != NO_TAG; FORWARD (q)) {
1681 if (NODE (q) != NO_NODE && strcmp (NSYMBOL (NODE (q)), sym) == 0) {
1682 intro_frame (f, p, a68g_link, printed);
1683 show_frame_item (f, p, a68g_link, q, PRIO (q));
1684 }
1685 }
1686 }
1687
1688
1689 //! @brief Search symbol in stack.
1690
1691 void examine_stack (FILE_T f, ADDR_T a68g_link, char *sym, int *printed)
1692 {
1693 if (a68g_link > 0) {
1694 int dynamic_a68g_link = FRAME_DYNAMIC_LINK (a68g_link);
1695 NODE_T *p = FRAME_TREE (a68g_link);
1696 if (p != NO_NODE) {
1697 TABLE_T *q = TABLE (p);
1698 examine_tags (f, p, a68g_link, IDENTIFIERS (q), sym, printed);
1699 examine_tags (f, p, a68g_link, OPERATORS (q), sym, printed);
1700 }
1701 examine_stack (f, dynamic_a68g_link, sym, printed);
1702 }
1703 }
1704
1705
1706 //! @brief Set or reset breakpoints.
1707
1708 void change_breakpoints (NODE_T * p, unt set, int num, BOOL_T * is_set, char *loc_expr)
1709 {
1710 for (; p != NO_NODE; FORWARD (p)) {
1711 change_breakpoints (SUB (p), set, num, is_set, loc_expr);
1712 if (set == BREAKPOINT_MASK) {
1713 if (LINE_NUMBER (p) == num && (STATUS_TEST (p, INTERRUPTIBLE_MASK)) && num != 0) {
1714 STATUS_SET (p, BREAKPOINT_MASK);
1715 a68g_free (EXPR (INFO (p)));
1716 EXPR (INFO (p)) = loc_expr;
1717 *is_set = A68G_TRUE;
1718 }
1719 } else if (set == BREAKPOINT_TEMPORARY_MASK) {
1720 if (LINE_NUMBER (p) == num && (STATUS_TEST (p, INTERRUPTIBLE_MASK)) && num != 0) {
1721 STATUS_SET (p, BREAKPOINT_TEMPORARY_MASK);
1722 a68g_free (EXPR (INFO (p)));
1723 EXPR (INFO (p)) = loc_expr;
1724 *is_set = A68G_TRUE;
1725 }
1726 } else if (set == NULL_MASK) {
1727 if (LINE_NUMBER (p) != num) {
1728 STATUS_CLEAR (p, (BREAKPOINT_MASK | BREAKPOINT_TEMPORARY_MASK));
1729 a68g_free (EXPR (INFO (p)));
1730 EXPR (INFO (p)) = NO_TEXT;
1731 } else if (num == 0) {
1732 STATUS_CLEAR (p, (BREAKPOINT_MASK | BREAKPOINT_TEMPORARY_MASK));
1733 a68g_free (EXPR (INFO (p)));
1734 EXPR (INFO (p)) = NO_TEXT;
1735 }
1736 }
1737 }
1738 }
1739
1740
1741 //! @brief List breakpoints.
1742
1743 void list_breakpoints (NODE_T * p, int *listed)
1744 {
1745 for (; p != NO_NODE; FORWARD (p)) {
1746 list_breakpoints (SUB (p), listed);
1747 if (STATUS_TEST (p, BREAKPOINT_MASK)) {
1748 (*listed)++;
1749 WIS (p);
1750 if (EXPR (INFO (p)) != NO_TEXT) {
1751 WRITELN (A68G_STDOUT, "breakpoint condition \"");
1752 WRITE (A68G_STDOUT, EXPR (INFO (p)));
1753 WRITE (A68G_STDOUT, "\"");
1754 }
1755 }
1756 }
1757 }
1758
1759
1760 //! @brief Execute monitor command.
1761
1762 BOOL_T single_stepper (NODE_T * p, char *cmd)
1763 {
1764 A68G_MON (mon_errors) = 0;
1765 errno = 0;
1766 if (strlen (cmd) == 0) {
1767 return A68G_FALSE;
1768 }
1769 while (IS_SPACE (cmd[strlen (cmd) - 1])) {
1770 cmd[strlen (cmd) - 1] = NULL_CHAR;
1771 }
1772 if (match_string (cmd, "CAlls", BLANK_CHAR)) {
1773 int k = get_num_arg (cmd, NO_REF);
1774 int printed = 0;
1775 if (k > 0) {
1776 stack_trace (A68G_STDOUT, A68G_FP, k, &printed);
1777 } else if (k == 0) {
1778 stack_trace (A68G_STDOUT, A68G_FP, 3, &printed);
1779 }
1780 return A68G_FALSE;
1781 } else if (match_string (cmd, "Continue", NULL_CHAR) || match_string (cmd, "Resume", NULL_CHAR)) {
1782 A68G (do_confirm_exit) = A68G_TRUE;
1783 return A68G_TRUE;
1784 } else if (match_string (cmd, "DO", BLANK_CHAR) || match_string (cmd, "EXEC", BLANK_CHAR)) {
1785 char *sym = cmd;
1786 SKIP_ONE_SYMBOL (sym);
1787 if (sym[0] != NULL_CHAR) {
1788 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "return code %d", system (sym)) >= 0);
1789 WRITELN (A68G_STDOUT, A68G (output_line));
1790 }
1791 return A68G_FALSE;
1792 } else if (match_string (cmd, "ELems", BLANK_CHAR)) {
1793 int k = get_num_arg (cmd, NO_REF);
1794 if (k > 0) {
1795 A68G_MON (max_row_elems) = k;
1796 }
1797 return A68G_FALSE;
1798 } else if (match_string (cmd, "Evaluate", BLANK_CHAR) || match_string (cmd, "X", BLANK_CHAR)) {
1799 char *sym = cmd;
1800 SKIP_ONE_SYMBOL (sym);
1801 if (sym[0] != NULL_CHAR) {
1802 ADDR_T old_sp = A68G_SP;
1803 evaluate (A68G_STDOUT, p, sym);
1804 if (A68G_MON (mon_errors) == 0 && A68G_MON (_m_sp) > 0) {
1805 BOOL_T cont = A68G_TRUE;
1806 while (cont) {
1807 MOID_T *res = A68G_MON (_m_stack)[0];
1808 WRITELN (A68G_STDOUT, "(");
1809 WRITE (A68G_STDOUT, moid_to_string (res, MOID_WIDTH, NO_NODE));
1810 WRITE (A68G_STDOUT, ")");
1811 show_item (A68G_STDOUT, p, STACK_ADDRESS (old_sp), res);
1812 cont = (BOOL_T) (IS_REF (res) && !IS_NIL (*(A68G_REF *) STACK_ADDRESS (old_sp)));
1813 if (cont) {
1814 A68G_REF z;
1815 POP_REF (p, &z);
1816 A68G_MON (_m_stack)[0] = SUB (A68G_MON (_m_stack)[0]);
1817 PUSH (p, ADDRESS (&z), SIZE (A68G_MON (_m_stack)[0]));
1818 }
1819 }
1820 } else {
1821 monitor_error (CANNOT_SHOW, NO_TEXT);
1822 }
1823 A68G_SP = old_sp;
1824 A68G_MON (_m_sp) = 0;
1825 }
1826 return A68G_FALSE;
1827 } else if (match_string (cmd, "EXamine", BLANK_CHAR)) {
1828 char *sym = cmd;
1829 SKIP_ONE_SYMBOL (sym);
1830 if (sym[0] != NULL_CHAR && (IS_LOWER (sym[0]) || IS_UPPER (sym[0]))) {
1831 int printed = 0;
1832 examine_stack (A68G_STDOUT, A68G_FP, sym, &printed);
1833 if (printed == 0) {
1834 monitor_error ("tag not found", sym);
1835 }
1836 } else {
1837 monitor_error ("tag expected", NO_TEXT);
1838 }
1839 return A68G_FALSE;
1840 } else if (match_string (cmd, "EXIt", NULL_CHAR) || match_string (cmd, "HX", NULL_CHAR) || match_string (cmd, "Quit", NULL_CHAR) || strcmp (cmd, LOGOUT_STRING) == 0) {
1841 if (confirm_exit ()) {
1842 exit_genie (p, A68G_RUNTIME_ERROR + A68G_FORCE_QUIT);
1843 }
1844 return A68G_FALSE;
1845 } else if (match_string (cmd, "Frame", NULL_CHAR)) {
1846 if (A68G_MON (current_frame) == 0) {
1847 int printed = 0;
1848 stack_dump (A68G_STDOUT, A68G_FP, 1, &printed);
1849 } else {
1850 stack_dump_current (A68G_STDOUT, A68G_FP);
1851 }
1852 return A68G_FALSE;
1853 } else if (match_string (cmd, "Frame", BLANK_CHAR)) {
1854 int n = get_num_arg (cmd, NO_REF);
1855 A68G_MON (current_frame) = (n > 0 ? n : 0);
1856 stack_dump_current (A68G_STDOUT, A68G_FP);
1857 return A68G_FALSE;
1858 } else if (match_string (cmd, "HEAp", BLANK_CHAR)) {
1859 int top = get_num_arg (cmd, NO_REF);
1860 if (top <= 0) {
1861 top = A68G (heap_size);
1862 }
1863 show_heap (A68G_STDOUT, p, A68G_GC (busy_handles), top, A68G (term_heigth) - 4);
1864 return A68G_FALSE;
1865 } else if (match_string (cmd, "APropos", NULL_CHAR) || match_string (cmd, "Help", NULL_CHAR) || match_string (cmd, "INfo", NULL_CHAR)) {
1866 apropos (A68G_STDOUT, NO_TEXT, "monitor");
1867 return A68G_FALSE;
1868 } else if (match_string (cmd, "APropos", BLANK_CHAR) || match_string (cmd, "Help", BLANK_CHAR) || match_string (cmd, "INfo", BLANK_CHAR)) {
1869 char *sym = cmd;
1870 SKIP_ONE_SYMBOL (sym);
1871 apropos (A68G_STDOUT, NO_TEXT, sym);
1872 return A68G_FALSE;
1873 } else if (match_string (cmd, "HT", NULL_CHAR)) {
1874 A68G (halt_typing) = A68G_TRUE;
1875 A68G (do_confirm_exit) = A68G_TRUE;
1876 return A68G_TRUE;
1877 } else if (match_string (cmd, "RT", NULL_CHAR)) {
1878 A68G (halt_typing) = A68G_FALSE;
1879 A68G (do_confirm_exit) = A68G_TRUE;
1880 return A68G_TRUE;
1881 } else if (match_string (cmd, "Breakpoint", BLANK_CHAR)) {
1882 char *sym = cmd;
1883 SKIP_ONE_SYMBOL (sym);
1884 if (sym[0] == NULL_CHAR) {
1885 int listed = 0;
1886 list_breakpoints (TOP_NODE (&A68G_JOB), &listed);
1887 if (listed == 0) {
1888 WRITELN (A68G_STDOUT, "No breakpoints set");
1889 }
1890 if (A68G_MON (watchpoint_expression) != NO_TEXT) {
1891 WRITELN (A68G_STDOUT, "Watchpoint condition \"");
1892 WRITE (A68G_STDOUT, A68G_MON (watchpoint_expression));
1893 WRITE (A68G_STDOUT, "\"");
1894 } else {
1895 WRITELN (A68G_STDOUT, "No watchpoint expression set");
1896 }
1897 } else if (IS_DIGIT (sym[0])) {
1898 char *mod;
1899 int k = get_num_arg (cmd, &mod);
1900 SKIP_SPACE (mod);
1901 if (mod[0] == NULL_CHAR) {
1902 BOOL_T set = A68G_FALSE;
1903 change_breakpoints (TOP_NODE (&A68G_JOB), BREAKPOINT_MASK, k, &set, NULL);
1904 if (set == A68G_FALSE) {
1905 monitor_error ("cannot set breakpoint in that line", NO_TEXT);
1906 }
1907 } else if (match_string (mod, "IF", BLANK_CHAR)) {
1908 char *cexpr = mod;
1909 BOOL_T set = A68G_FALSE;
1910 SKIP_ONE_SYMBOL (cexpr);
1911 change_breakpoints (TOP_NODE (&A68G_JOB), BREAKPOINT_MASK, k, &set, new_string (cexpr, NO_TEXT));
1912 if (set == A68G_FALSE) {
1913 monitor_error ("cannot set breakpoint in that line", NO_TEXT);
1914 }
1915 } else if (match_string (mod, "Clear", NULL_CHAR)) {
1916 change_breakpoints (TOP_NODE (&A68G_JOB), NULL_MASK, k, NULL, NULL);
1917 } else {
1918 monitor_error ("invalid breakpoint command", NO_TEXT);
1919 }
1920 } else if (match_string (sym, "List", NULL_CHAR)) {
1921 int listed = 0;
1922 list_breakpoints (TOP_NODE (&A68G_JOB), &listed);
1923 if (listed == 0) {
1924 WRITELN (A68G_STDOUT, "No breakpoints set");
1925 }
1926 if (A68G_MON (watchpoint_expression) != NO_TEXT) {
1927 WRITELN (A68G_STDOUT, "Watchpoint condition \"");
1928 WRITE (A68G_STDOUT, A68G_MON (watchpoint_expression));
1929 WRITE (A68G_STDOUT, "\"");
1930 } else {
1931 WRITELN (A68G_STDOUT, "No watchpoint expression set");
1932 }
1933 } else if (match_string (sym, "Watch", BLANK_CHAR)) {
1934 char *cexpr = sym;
1935 SKIP_ONE_SYMBOL (cexpr);
1936 a68g_free (A68G_MON (watchpoint_expression));
1937 A68G_MON (watchpoint_expression) = NO_TEXT;
1938 A68G_MON (watchpoint_expression) = new_string (cexpr, NO_TEXT);
1939 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_WATCH_MASK, A68G_TRUE);
1940 } else if (match_string (sym, "Clear", BLANK_CHAR)) {
1941 char *mod = sym;
1942 SKIP_ONE_SYMBOL (mod);
1943 if (mod[0] == NULL_CHAR) {
1944 change_breakpoints (TOP_NODE (&A68G_JOB), NULL_MASK, 0, NULL, NULL);
1945 a68g_free (A68G_MON (watchpoint_expression));
1946 A68G_MON (watchpoint_expression) = NO_TEXT;
1947 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_WATCH_MASK, A68G_FALSE);
1948 } else if (match_string (mod, "ALL", NULL_CHAR)) {
1949 change_breakpoints (TOP_NODE (&A68G_JOB), NULL_MASK, 0, NULL, NULL);
1950 a68g_free (A68G_MON (watchpoint_expression));
1951 A68G_MON (watchpoint_expression) = NO_TEXT;
1952 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_WATCH_MASK, A68G_FALSE);
1953 } else if (match_string (mod, "Breakpoints", NULL_CHAR)) {
1954 change_breakpoints (TOP_NODE (&A68G_JOB), NULL_MASK, 0, NULL, NULL);
1955 } else if (match_string (mod, "Watchpoint", NULL_CHAR)) {
1956 a68g_free (A68G_MON (watchpoint_expression));
1957 A68G_MON (watchpoint_expression) = NO_TEXT;
1958 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_WATCH_MASK, A68G_FALSE);
1959 } else {
1960 monitor_error ("invalid breakpoint command", NO_TEXT);
1961 }
1962 } else {
1963 monitor_error ("invalid breakpoint command", NO_TEXT);
1964 }
1965 return A68G_FALSE;
1966 } else if (match_string (cmd, "List", BLANK_CHAR)) {
1967 char *cwhere;
1968 int n = get_num_arg (cmd, &cwhere);
1969 int m = get_num_arg (cwhere, NO_REF);
1970 if (m == NOT_A_NUM) {
1971 if (n > 0) {
1972 list (A68G_STDOUT, p, n, 0);
1973 } else if (n == NOT_A_NUM) {
1974 list (A68G_STDOUT, p, 10, 0);
1975 }
1976 } else if (n > 0 && m > 0 && n <= m) {
1977 list (A68G_STDOUT, p, n, m);
1978 }
1979 return A68G_FALSE;
1980 } else if (match_string (cmd, "PROmpt", BLANK_CHAR)) {
1981 char *sym = cmd;
1982 SKIP_ONE_SYMBOL (sym);
1983 if (sym[0] != NULL_CHAR) {
1984 if (sym[0] == QUOTE_CHAR) {
1985 sym++;
1986 }
1987 size_t len = strlen (sym);
1988 if (len > 0 && sym[len - 1] == QUOTE_CHAR) {
1989 sym[len - 1] = NULL_CHAR;
1990 }
1991 a68g_bufcpy (A68G_MON (prompt), sym, BUFFER_SIZE);
1992 }
1993 return A68G_FALSE;
1994 } else if (match_string (cmd, "RERun", NULL_CHAR) || match_string (cmd, "REStart", NULL_CHAR)) {
1995 if (confirm_exit ()) {
1996 exit_genie (p, A68G_RERUN);
1997 }
1998 return A68G_FALSE;
1999 } else if (match_string (cmd, "RESET", NULL_CHAR)) {
2000 if (confirm_exit ()) {
2001 change_breakpoints (TOP_NODE (&A68G_JOB), NULL_MASK, 0, NULL, NULL);
2002 a68g_free (A68G_MON (watchpoint_expression));
2003 A68G_MON (watchpoint_expression) = NO_TEXT;
2004 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_WATCH_MASK, A68G_FALSE);
2005 exit_genie (p, A68G_RERUN);
2006 }
2007 return A68G_FALSE;
2008 } else if (match_string (cmd, "LINk", BLANK_CHAR)) {
2009 int k = get_num_arg (cmd, NO_REF), printed = 0;
2010 if (k > 0) {
2011 stack_a68g_link_dump (A68G_STDOUT, A68G_FP, k, &printed);
2012 } else if (k == NOT_A_NUM) {
2013 stack_a68g_link_dump (A68G_STDOUT, A68G_FP, 3, &printed);
2014 }
2015 return A68G_FALSE;
2016 } else if (match_string (cmd, "STAck", BLANK_CHAR) || match_string (cmd, "BT", BLANK_CHAR)) {
2017 int k = get_num_arg (cmd, NO_REF), printed = 0;
2018 if (k > 0) {
2019 stack_dump (A68G_STDOUT, A68G_FP, k, &printed);
2020 } else if (k == NOT_A_NUM) {
2021 stack_dump (A68G_STDOUT, A68G_FP, 3, &printed);
2022 }
2023 return A68G_FALSE;
2024 } else if (match_string (cmd, "Next", NULL_CHAR)) {
2025 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_TEMPORARY_MASK, A68G_TRUE);
2026 A68G (do_confirm_exit) = A68G_FALSE;
2027 A68G_MON (break_proc_level) = PROCEDURE_LEVEL (INFO (p));
2028 return A68G_TRUE;
2029 } else if (match_string (cmd, "STEp", NULL_CHAR)) {
2030 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_TEMPORARY_MASK, A68G_TRUE);
2031 A68G (do_confirm_exit) = A68G_FALSE;
2032 return A68G_TRUE;
2033 } else if (match_string (cmd, "FINish", NULL_CHAR) || match_string (cmd, "OUT", NULL_CHAR)) {
2034 A68G_MON (finish_frame_pointer) = FRAME_PARAMETERS (A68G_FP);
2035 A68G (do_confirm_exit) = A68G_FALSE;
2036 return A68G_TRUE;
2037 } else if (match_string (cmd, "Until", BLANK_CHAR)) {
2038 int k = get_num_arg (cmd, NO_REF);
2039 if (k > 0) {
2040 BOOL_T set = A68G_FALSE;
2041 change_breakpoints (TOP_NODE (&A68G_JOB), BREAKPOINT_TEMPORARY_MASK, k, &set, NULL);
2042 if (set == A68G_FALSE) {
2043 monitor_error ("cannot set breakpoint in that line", NO_TEXT);
2044 return A68G_FALSE;
2045 }
2046 A68G (do_confirm_exit) = A68G_FALSE;
2047 return A68G_TRUE;
2048 } else {
2049 monitor_error ("line number expected", NO_TEXT);
2050 return A68G_FALSE;
2051 }
2052 } else if (match_string (cmd, "Where", NULL_CHAR)) {
2053 WIS (p);
2054 return A68G_FALSE;
2055 } else if (strcmp (cmd, "?") == 0) {
2056 apropos (A68G_STDOUT, A68G_MON (prompt), "monitor");
2057 return A68G_FALSE;
2058 } else if (match_string (cmd, "Sizes", NULL_CHAR)) {
2059 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Frame stack pointer=" A68G_LU " available=" A68G_LU, A68G_FP, A68G (frame_stack_size) - A68G_FP) >= 0);
2060 WRITELN (A68G_STDOUT, A68G (output_line));
2061 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Expression stack pointer=" A68G_LU " available=" A68G_LU, A68G_SP, (UNSIGNED_T) (A68G (expr_stack_size) - A68G_SP)) >= 0);
2062 WRITELN (A68G_STDOUT, A68G (output_line));
2063 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Heap size=%u available=%u", A68G (heap_size), heap_available ()) >= 0);
2064 WRITELN (A68G_STDOUT, A68G (output_line));
2065 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Garbage collections=" A68G_LD, A68G_GC (sweeps)) >= 0);
2066 WRITELN (A68G_STDOUT, A68G (output_line));
2067 return A68G_FALSE;
2068 } else if (match_string (cmd, "XRef", NULL_CHAR)) {
2069 int k = LINE_NUMBER (p);
2070 for (LINE_T *line = TOP_LINE (&A68G_JOB); line != NO_LINE; FORWARD (line)) {
2071 if (NUMBER (line) > 0 && NUMBER (line) == k) {
2072 list_source_line (A68G_STDOUT, line, A68G_TRUE);
2073 }
2074 }
2075 return A68G_FALSE;
2076 } else if (match_string (cmd, "XRef", BLANK_CHAR)) {
2077 int k = get_num_arg (cmd, NO_REF);
2078 if (k == NOT_A_NUM) {
2079 monitor_error ("line number expected", NO_TEXT);
2080 } else {
2081 for (LINE_T *line = TOP_LINE (&A68G_JOB); line != NO_LINE; FORWARD (line)) {
2082 if (NUMBER (line) > 0 && NUMBER (line) == k) {
2083 list_source_line (A68G_STDOUT, line, A68G_TRUE);
2084 }
2085 }
2086 }
2087 return A68G_FALSE;
2088 } else if (strlen (cmd) == 0) {
2089 return A68G_FALSE;
2090 } else {
2091 monitor_error ("unrecognised command", NO_TEXT);
2092 return A68G_FALSE;
2093 }
2094 }
2095
2096
2097 //! @brief Evaluate conditional breakpoint expression.
2098
2099 BOOL_T evaluate_breakpoint_expression (NODE_T * p)
2100 {
2101 ADDR_T top_sp = A68G_SP;
2102 volatile BOOL_T res = A68G_FALSE;
2103 A68G_MON (mon_errors) = 0;
2104 if (EXPR (INFO (p)) != NO_TEXT) {
2105 evaluate (A68G_STDOUT, p, EXPR (INFO (p)));
2106 if (A68G_MON (_m_sp) != 1 || A68G_MON (mon_errors) != 0) {
2107 A68G_MON (mon_errors) = 0;
2108 monitor_error ("deleted invalid breakpoint expression", NO_TEXT);
2109 a68g_free (EXPR (INFO (p)));
2110 EXPR (INFO (p)) = A68G_MON (expr);
2111 res = A68G_TRUE;
2112 } else if (TOP_MODE == M_BOOL) {
2113 A68G_BOOL z;
2114 POP_OBJECT (p, &z, A68G_BOOL);
2115 res = (BOOL_T) (STATUS (&z) == INIT_MASK && VALUE (&z) == A68G_TRUE);
2116 } else {
2117 monitor_error ("deleted invalid breakpoint expression yielding mode", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
2118 a68g_free (EXPR (INFO (p)));
2119 EXPR (INFO (p)) = A68G_MON (expr);
2120 res = A68G_TRUE;
2121 }
2122 }
2123 A68G_SP = top_sp;
2124 return res;
2125 }
2126
2127
2128 //! @brief Evaluate conditional watchpoint expression.
2129
2130 BOOL_T evaluate_watchpoint_expression (NODE_T * p)
2131 {
2132 ADDR_T top_sp = A68G_SP;
2133 volatile BOOL_T res = A68G_FALSE;
2134 A68G_MON (mon_errors) = 0;
2135 if (A68G_MON (watchpoint_expression) != NO_TEXT) {
2136 evaluate (A68G_STDOUT, p, A68G_MON (watchpoint_expression));
2137 if (A68G_MON (_m_sp) != 1 || A68G_MON (mon_errors) != 0) {
2138 A68G_MON (mon_errors) = 0;
2139 monitor_error ("deleted invalid watchpoint expression", NO_TEXT);
2140 a68g_free (A68G_MON (watchpoint_expression));
2141 A68G_MON (watchpoint_expression) = NO_TEXT;
2142 res = A68G_TRUE;
2143 }
2144 if (TOP_MODE == M_BOOL) {
2145 A68G_BOOL z;
2146 POP_OBJECT (p, &z, A68G_BOOL);
2147 res = (BOOL_T) (STATUS (&z) == INIT_MASK && VALUE (&z) == A68G_TRUE);
2148 } else {
2149 monitor_error ("deleted invalid watchpoint expression yielding mode", moid_to_string (TOP_MODE, MOID_WIDTH, NO_NODE));
2150 a68g_free (A68G_MON (watchpoint_expression));
2151 A68G_MON (watchpoint_expression) = NO_TEXT;
2152 res = A68G_TRUE;
2153 }
2154 }
2155 A68G_SP = top_sp;
2156 return res;
2157 }
2158
2159
2160 //! @brief Execute monitor.
2161
2162 void single_step (NODE_T * p, unt mask)
2163 {
2164 volatile BOOL_T do_cmd = A68G_TRUE;
2165 ADDR_T top_sp = A68G_SP;
2166 A68G_MON (current_frame) = 0;
2167 A68G_MON (max_row_elems) = MAX_ROW_ELEMS;
2168 A68G_MON (mon_errors) = 0;
2169 A68G_MON (tabs) = 0;
2170 A68G_MON (prompt_set) = A68G_FALSE;
2171 if (LINE_NUMBER (p) == 0) {
2172 return;
2173 }
2174 #if defined (HAVE_CURSES)
2175 genie_curses_end (NO_NODE);
2176 #endif
2177 if (mask == (UNSIGNED_T) BREAKPOINT_ERROR_MASK) {
2178 WRITELN (A68G_STDOUT, "Monitor entered after an error");
2179 WIS ((p));
2180 } else if ((mask & BREAKPOINT_INTERRUPT_MASK) != 0) {
2181 WRITELN (A68G_STDOUT, NEWLINE_STRING);
2182 WIS ((p));
2183 if (A68G (do_confirm_exit) && confirm_exit ()) {
2184 exit_genie ((p), A68G_RUNTIME_ERROR + A68G_FORCE_QUIT);
2185 }
2186 } else if ((mask & BREAKPOINT_MASK) != 0) {
2187 if (EXPR (INFO (p)) != NO_TEXT) {
2188 if (!evaluate_breakpoint_expression (p)) {
2189 return;
2190 }
2191 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Breakpoint (%s)", EXPR (INFO (p))) >= 0);
2192 } else {
2193 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Breakpoint") >= 0);
2194 }
2195 WRITELN (A68G_STDOUT, A68G (output_line));
2196 WIS (p);
2197 } else if ((mask & BREAKPOINT_TEMPORARY_MASK) != 0) {
2198 if (A68G_MON (break_proc_level) != 0 && PROCEDURE_LEVEL (INFO (p)) > A68G_MON (break_proc_level)) {
2199 return;
2200 }
2201 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_TEMPORARY_MASK, A68G_FALSE);
2202 WRITELN (A68G_STDOUT, "Temporary breakpoint (now removed)");
2203 WIS (p);
2204 } else if ((mask & BREAKPOINT_WATCH_MASK) != 0) {
2205 if (!evaluate_watchpoint_expression (p)) {
2206 return;
2207 }
2208 if (A68G_MON (watchpoint_expression) != NO_TEXT) {
2209 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Watchpoint (%s)", A68G_MON (watchpoint_expression)) >= 0);
2210 } else {
2211 ASSERT (a68g_bufprt (A68G (output_line), SNPRINTF_SIZE, "Watchpoint (now removed)") >= 0);
2212 }
2213 WRITELN (A68G_STDOUT, A68G (output_line));
2214 WIS (p);
2215 } else if ((mask & BREAKPOINT_TRACE_MASK) != 0) {
2216 PROP_T *prop = &GPROP (p);
2217 WIS ((p));
2218 if (propagator_name ((PROP_PROC *) UNIT (prop)) != NO_TEXT) {
2219 WRITELN (A68G_STDOUT, propagator_name ((PROP_PROC *) UNIT (prop)));
2220 }
2221 return;
2222 } else {
2223 WRITELN (A68G_STDOUT, "Monitor entered with no valid reason (continuing execution)");
2224 WIS ((p));
2225 return;
2226 }
2227 #if defined (BUILD_PARALLEL_CLAUSE)
2228 if (is_main_thread ()) {
2229 WRITELN (A68G_STDOUT, "This is the main thread");
2230 } else {
2231 WRITELN (A68G_STDOUT, "This is not the main thread");
2232 }
2233 #endif
2234 // Entry into the monitor.
2235 if (A68G_MON (prompt_set) == A68G_FALSE) {
2236 a68g_bufcpy (A68G_MON (prompt), "(a68g) ", BUFFER_SIZE);
2237 A68G_MON (prompt_set) = A68G_TRUE;
2238 }
2239 A68G_MON (in_monitor) = A68G_TRUE;
2240 A68G_MON (break_proc_level) = 0;
2241 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_INTERRUPT_MASK, A68G_FALSE);
2242 STATUS_CLEAR (TOP_NODE (&A68G_JOB), BREAKPOINT_INTERRUPT_MASK);
2243 while (do_cmd) {
2244 char *cmd;
2245 A68G_SP = top_sp;
2246 io_close_tty_line ();
2247 while (strlen (cmd = read_string_from_tty (A68G_MON (prompt))) == 0) {;
2248 }
2249 if (TO_UCHAR (cmd[0]) == TO_UCHAR (EOF_CHAR)) {
2250 a68g_bufcpy (cmd, LOGOUT_STRING, BUFFER_SIZE);
2251 WRITE (A68G_STDOUT, LOGOUT_STRING);
2252 WRITE (A68G_STDOUT, NEWLINE_STRING);
2253 }
2254 A68G_MON (_m_sp) = 0;
2255 do_cmd = (BOOL_T) (!single_stepper (p, cmd));
2256 }
2257 A68G_SP = top_sp;
2258 A68G_MON (in_monitor) = A68G_FALSE;
2259 if (mask == (UNSIGNED_T) BREAKPOINT_ERROR_MASK) {
2260 WRITELN (A68G_STDOUT, "Continuing from an error might corrupt things");
2261 single_step (p, (UNSIGNED_T) BREAKPOINT_ERROR_MASK);
2262 } else {
2263 WRITELN (A68G_STDOUT, "Continuing ...");
2264 WRITELN (A68G_STDOUT, "");
2265 }
2266 }
2267
2268
2269 //! @brief PROC debug = VOID
2270
2271 void genie_debug (NODE_T * p)
2272 {
2273 single_step (p, BREAKPOINT_INTERRUPT_MASK);
2274 }
2275
2276
2277 //! @brief PROC break = VOID
2278
2279 void genie_break (NODE_T * p)
2280 {
2281 (void) p;
2282 change_masks (TOP_NODE (&A68G_JOB), BREAKPOINT_INTERRUPT_MASK, A68G_TRUE);
2283 }
2284
2285
2286 //! @brief PROC evaluate = (STRING) STRING
2287
2288 void genie_evaluate (NODE_T * p)
2289 {
2290 // Pop argument.
2291 A68G_REF u;
2292 POP_REF (p, (A68G_REF *) & u);
2293 volatile ADDR_T top_sp = A68G_SP;
2294 CHECK_MON_REF (p, u, M_STRING);
2295 reset_transput_buffer (UNFORMATTED_BUFFER);
2296 add_a_string_transput_buffer (p, UNFORMATTED_BUFFER, (BYTE_T *) & u);
2297 A68G_REF v = c_to_a_string (p, get_transput_buffer (UNFORMATTED_BUFFER), DEFAULT_WIDTH);
2298 // Evaluate in the monitor.
2299 A68G_MON (in_monitor) = A68G_TRUE;
2300 A68G_MON (mon_errors) = 0;
2301 evaluate (A68G_STDOUT, p, get_transput_buffer (UNFORMATTED_BUFFER));
2302 A68G_MON (in_monitor) = A68G_FALSE;
2303 if (A68G_MON (_m_sp) != 1) {
2304 monitor_error ("invalid expression", NO_TEXT);
2305 }
2306 if (A68G_MON (mon_errors) == 0) {
2307 BOOL_T cont = A68G_TRUE;
2308 while (cont) {
2309 MOID_T *res = TOP_MODE;
2310 cont = (BOOL_T) (IS_REF (res) && !IS_NIL (*(A68G_REF *) STACK_ADDRESS (top_sp)));
2311 if (cont) {
2312 A68G_REF w;
2313 POP_REF (p, &w);
2314 TOP_MODE = SUB (TOP_MODE);
2315 PUSH (p, ADDRESS (&w), SIZE (TOP_MODE));
2316 }
2317 }
2318 reset_transput_buffer (UNFORMATTED_BUFFER);
2319 genie_write_standard (p, TOP_MODE, STACK_ADDRESS (top_sp), nil_ref);
2320 v = c_to_a_string (p, get_transput_buffer (UNFORMATTED_BUFFER), DEFAULT_WIDTH);
2321 }
2322 A68G_SP = top_sp;
2323 PUSH_REF (p, v);
2324 }
© J.M. van der Veer • jmvdveer@algol68genie.nl