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