genie.c

     
   1  //! @file genie.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-2024 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  //! Interpreter driver.
  25  
  26  // This file contains interpreter ("genie") routines related to executing primitive
  27  // A68 actions.
  28  // 
  29  // The genie is self-optimising as when it traverses the tree, it stores terminals
  30  // it ends up in at the root where traversing for that terminal started.
  31  // Such piece of information is called a PROP.
  32  
  33  #include "a68g.h"
  34  #include "a68g-genie.h"
  35  #include "a68g-frames.h"
  36  #include "a68g-prelude.h"
  37  #include "a68g-mp.h"
  38  #include "a68g-parser.h"
  39  #include "a68g-transput.h"
  40  
  41  //! @brief Set flags throughout tree.
  42  
  43  void change_masks (NODE_T * p, unt mask, BOOL_T set)
  44  {
  45    for (; p != NO_NODE; FORWARD (p)) {
  46      change_masks (SUB (p), mask, set);
  47      if (LINE_NUMBER (p) > 0) {
  48        if (set == A68_TRUE) {
  49          STATUS_SET (p, mask);
  50        } else {
  51          STATUS_CLEAR (p, mask);
  52        }
  53      }
  54    }
  55  }
  56  
  57  //! @brief Set flags throughout tree.
  58  
  59  void change_gc_masks (NODE_T * p, BOOL_T set)
  60  {
  61    for (; p != NO_NODE; FORWARD (p)) {
  62      switch (ATTRIBUTE (p)) {
  63        case CALL: {
  64            change_gc_masks (SUB (p), A68_TRUE);
  65            break;
  66          }
  67        case SLICE: {
  68            change_gc_masks (SUB (p), A68_TRUE);
  69            break;
  70          }
  71        default: {
  72          change_gc_masks (SUB (p), set);
  73          break;
  74        }
  75      }
  76      if (LINE_NUMBER (p) > 0) {
  77        if (set == A68_TRUE) {
  78          STATUS_SET (p, BLOCK_GC_MASK);
  79        } else {
  80          STATUS_CLEAR (p, BLOCK_GC_MASK);
  81        }
  82      }
  83    }
  84  }
  85  
  86  //! @brief Leave interpretation.
  87  
  88  void exit_genie (NODE_T * p, int ret)
  89  {
  90  #if defined (HAVE_CURSES)
  91    genie_curses_end (p);
  92  #endif
  93    A68 (close_tty_on_exit) = A68_TRUE;
  94    if (!A68 (in_execution)) {
  95      return;
  96    }
  97    if (ret == A68_RUNTIME_ERROR && A68 (in_monitor)) {
  98      return;
  99    } else if (ret == A68_RUNTIME_ERROR && OPTION_DEBUG (&A68_JOB)) {
 100      diagnostics_to_terminal (TOP_LINE (&A68_JOB), A68_RUNTIME_ERROR);
 101      single_step (p, (unt) BREAKPOINT_ERROR_MASK);
 102      A68 (in_execution) = A68_FALSE;
 103      A68 (ret_line_number) = LINE_NUMBER (p);
 104      A68 (ret_code) = ret;
 105      longjmp (A68 (genie_exit_label), 1);
 106    } else {
 107      if ((ret & A68_FORCE_QUIT) != NULL_MASK) {
 108        ret &= ~A68_FORCE_QUIT;
 109      }
 110  #if defined (BUILD_PARALLEL_CLAUSE)
 111      if (!is_main_thread ()) {
 112        genie_set_exit_from_threads (ret);
 113      } else {
 114        A68 (in_execution) = A68_FALSE;
 115        A68 (ret_line_number) = LINE_NUMBER (p);
 116        A68 (ret_code) = ret;
 117        longjmp (A68 (genie_exit_label), 1);
 118      }
 119  #else
 120      A68 (in_execution) = A68_FALSE;
 121      A68 (ret_line_number) = LINE_NUMBER (p);
 122      A68 (ret_code) = ret;
 123      longjmp (A68 (genie_exit_label), 1);
 124  #endif
 125    }
 126  }
 127  
 128  //! @brief Genie init rng.
 129  
 130  void genie_init_rng (void)
 131  {
 132    time_t t;
 133    if (time (&t) != -1) {
 134      init_rng ((unt) t);
 135    }
 136  }
 137  
 138  //! @brief Tie label to the clause it is defined in.
 139  
 140  void tie_label_to_serial (NODE_T * p)
 141  {
 142    for (; p != NO_NODE; FORWARD (p)) {
 143      if (IS (p, SERIAL_CLAUSE)) {
 144        BOOL_T valid_follow;
 145        if (NEXT (p) == NO_NODE) {
 146          valid_follow = A68_TRUE;
 147        } else if (IS (NEXT (p), CLOSE_SYMBOL)) {
 148          valid_follow = A68_TRUE;
 149        } else if (IS (NEXT (p), END_SYMBOL)) {
 150          valid_follow = A68_TRUE;
 151        } else if (IS (NEXT (p), EDOC_SYMBOL)) {
 152          valid_follow = A68_TRUE;
 153        } else if (IS (NEXT (p), OD_SYMBOL)) {
 154          valid_follow = A68_TRUE;
 155        } else {
 156          valid_follow = A68_FALSE;
 157        }
 158        if (valid_follow) {
 159          JUMP_TO (TABLE (SUB (p))) = NO_NODE;
 160        }
 161      }
 162      tie_label_to_serial (SUB (p));
 163    }
 164  }
 165  
 166  //! @brief Tie label to the clause it is defined in.
 167  
 168  void tie_label (NODE_T * p, NODE_T * unit)
 169  {
 170    for (; p != NO_NODE; FORWARD (p)) {
 171      if (IS (p, DEFINING_IDENTIFIER)) {
 172        UNIT (TAX (p)) = unit;
 173      }
 174      tie_label (SUB (p), unit);
 175    }
 176  }
 177  
 178  //! @brief Tie label to the clause it is defined in.
 179  
 180  void tie_label_to_unit (NODE_T * p)
 181  {
 182    for (; p != NO_NODE; FORWARD (p)) {
 183      if (IS (p, LABELED_UNIT)) {
 184        tie_label (SUB_SUB (p), NEXT_SUB (p));
 185      }
 186      tie_label_to_unit (SUB (p));
 187    }
 188  }
 189  
 190  //! @brief Fast way to indicate a mode.
 191  
 192  int mode_attribute (MOID_T * p)
 193  {
 194    if (IS_REF (p)) {
 195      return REF_SYMBOL;
 196    } else if (IS (p, PROC_SYMBOL)) {
 197      return PROC_SYMBOL;
 198    } else if (IS_UNION (p)) {
 199      return UNION_SYMBOL;
 200    } else if (p == M_INT) {
 201      return MODE_INT;
 202    } else if (p == M_LONG_INT) {
 203      return MODE_LONG_INT;
 204    } else if (p == M_LONG_LONG_INT) {
 205      return MODE_LONG_LONG_INT;
 206    } else if (p == M_REAL) {
 207      return MODE_REAL;
 208    } else if (p == M_LONG_REAL) {
 209      return MODE_LONG_REAL;
 210    } else if (p == M_LONG_LONG_REAL) {
 211      return MODE_LONG_LONG_REAL;
 212    } else if (p == M_COMPLEX) {
 213      return MODE_COMPLEX;
 214    } else if (p == M_LONG_COMPLEX) {
 215      return MODE_LONG_COMPLEX;
 216    } else if (p == M_LONG_LONG_COMPLEX) {
 217      return MODE_LONG_LONG_COMPLEX;
 218    } else if (p == M_BOOL) {
 219      return MODE_BOOL;
 220    } else if (p == M_CHAR) {
 221      return MODE_CHAR;
 222    } else if (p == M_BITS) {
 223      return MODE_BITS;
 224    } else if (p == M_LONG_BITS) {
 225      return MODE_LONG_BITS;
 226    } else if (p == M_LONG_LONG_BITS) {
 227      return MODE_LONG_LONG_BITS;
 228    } else if (p == M_BYTES) {
 229      return MODE_BYTES;
 230    } else if (p == M_LONG_BYTES) {
 231      return MODE_LONG_BYTES;
 232    } else if (p == M_FILE) {
 233      return MODE_FILE;
 234    } else if (p == M_FORMAT) {
 235      return MODE_FORMAT;
 236    } else if (p == M_PIPE) {
 237      return MODE_PIPE;
 238    } else if (p == M_SOUND) {
 239      return MODE_SOUND;
 240    } else {
 241      return MODE_NO_CHECK;
 242    }
 243  }
 244  
 245  //! @brief Perform tasks before interpretation.
 246  
 247  void genie_preprocess (NODE_T * p, int *max_lev, void *compile_plugin)
 248  {
 249  #if defined (BUILD_A68_COMPILER)
 250    static char *last_compile_name = NO_TEXT;
 251    static PROP_PROC *last_compile_unit = NO_PPROC;
 252  #endif
 253    for (; p != NO_NODE; FORWARD (p)) {
 254      if (STATUS_TEST (p, BREAKPOINT_MASK)) {
 255        if (!(STATUS_TEST (p, INTERRUPTIBLE_MASK))) {
 256          STATUS_CLEAR (p, BREAKPOINT_MASK);
 257        }
 258      }
 259      if (GINFO (p) != NO_GINFO) {
 260        IS_COERCION (GINFO (p)) = is_coercion (p);
 261        IS_NEW_LEXICAL_LEVEL (GINFO (p)) = is_new_lexical_level (p);
 262  // The default.
 263        UNIT (&GPROP (p)) = genie_unit;
 264        SOURCE (&GPROP (p)) = p;
 265  #if defined (BUILD_A68_COMPILER)
 266        if (OPTION_OPT_LEVEL (&A68_JOB) > 0 && COMPILE_NAME (GINFO (p)) != NO_TEXT && compile_plugin != NULL) {
 267          if (COMPILE_NAME (GINFO (p)) == last_compile_name) {
 268  // We copy.
 269            UNIT (&GPROP (p)) = last_compile_unit;
 270          } else {
 271  // We look up.
 272  // Next line may provoke a warning even with this POSIX workaround. Tant pis.
 273            *(void **) &(UNIT (&GPROP (p))) = dlsym (compile_plugin, COMPILE_NAME (GINFO (p)));
 274            ABEND (UNIT (&GPROP (p)) == NULL, ERROR_INTERNAL_CONSISTENCY, dlerror ());
 275            last_compile_name = COMPILE_NAME (GINFO (p));
 276            last_compile_unit = UNIT (&GPROP (p));
 277          }
 278        }
 279  #endif
 280      }
 281      if (MOID (p) != NO_MOID) {
 282        SIZE (MOID (p)) = moid_size (MOID (p));
 283        DIGITS (MOID (p)) = moid_digits (MOID (p));
 284        SHORT_ID (MOID (p)) = mode_attribute (MOID (p));
 285        if (GINFO (p) != NO_GINFO) {
 286          NEED_DNS (GINFO (p)) = A68_FALSE;
 287          if (IS_REF (MOID (p))) {
 288            NEED_DNS (GINFO (p)) = A68_TRUE;
 289          } else if (IS (MOID (p), PROC_SYMBOL)) {
 290            NEED_DNS (GINFO (p)) = A68_TRUE;
 291          } else if (IS (MOID (p), FORMAT_SYMBOL)) {
 292            NEED_DNS (GINFO (p)) = A68_TRUE;
 293          }
 294        }
 295      }
 296      if (TABLE (p) != NO_TABLE) {
 297        if (LEX_LEVEL (p) > *max_lev) {
 298          *max_lev = LEX_LEVEL (p);
 299        }
 300      }
 301      if (IS (p, FORMAT_TEXT)) {
 302        TAG_T *q = TAX (p);
 303        if (q != NO_TAG && NODE (q) != NO_NODE) {
 304          NODE (q) = p;
 305        }
 306      } else if (IS (p, DEFINING_IDENTIFIER)) {
 307        TAG_T *q = TAX (p);
 308        if (q != NO_TAG && NODE (q) != NO_NODE && TABLE (NODE (q)) != NO_TABLE) {
 309          LEVEL (GINFO (p)) = LEX_LEVEL (NODE (q));
 310        }
 311      } else if (IS (p, IDENTIFIER)) {
 312        TAG_T *q = TAX (p);
 313        if (q != NO_TAG && NODE (q) != NO_NODE && TABLE (NODE (q)) != NO_TABLE) {
 314          LEVEL (GINFO (p)) = LEX_LEVEL (NODE (q));
 315          OFFSET (GINFO (p)) = &(A68_STACK[FRAME_INFO_SIZE + OFFSET (q)]);
 316        }
 317      } else if (IS (p, OPERATOR)) {
 318        TAG_T *q = TAX (p);
 319        if (q != NO_TAG && NODE (q) != NO_NODE && TABLE (NODE (q)) != NO_TABLE) {
 320          LEVEL (GINFO (p)) = LEX_LEVEL (NODE (q));
 321          OFFSET (GINFO (p)) = &(A68_STACK[FRAME_INFO_SIZE + OFFSET (q)]);
 322        }
 323      }
 324      if (SUB (p) != NO_NODE) {
 325        if (GINFO (p) != NO_GINFO) {
 326          GPARENT (SUB (p)) = p;
 327        }
 328        genie_preprocess (SUB (p), max_lev, compile_plugin);
 329      }
 330    }
 331  }
 332  
 333  //! @brief Get outermost lexical level in the user program.
 334  
 335  void get_global_level (NODE_T * p)
 336  {
 337    for (; p != NO_NODE; FORWARD (p)) {
 338      if (LINE_NUMBER (p) != 0 && IS (p, UNIT)) {
 339        if (LEX_LEVEL (p) < A68 (global_level)) {
 340          A68 (global_level) = LEX_LEVEL (p);
 341        }
 342      }
 343      get_global_level (SUB (p));
 344    }
 345  }
 346  
 347  //! @brief Driver for the interpreter.
 348  
 349  void genie (void *compile_plugin)
 350  {
 351  // Fill in final info for modes.
 352    for (MOID_T *m = TOP_MOID (&A68_JOB); m != NO_MOID; FORWARD (m)) {
 353      SIZE (m) = moid_size (m);
 354      DIGITS (m) = moid_digits (m);
 355      SHORT_ID (m) = mode_attribute (m);
 356    }
 357  // Preprocessing.
 358    A68 (max_lex_lvl) = 0;
 359  //  genie_lex_levels (TOP_NODE (&A68_JOB), 1);.
 360    genie_preprocess (TOP_NODE (&A68_JOB), &A68 (max_lex_lvl), compile_plugin);
 361    change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_INTERRUPT_MASK, A68_FALSE);
 362    change_gc_masks (TOP_NODE (&A68_JOB), A68_FALSE);
 363    A68_MON (watchpoint_expression) = NO_TEXT;
 364    A68 (frame_stack_limit) = A68 (frame_end) - A68 (storage_overhead);
 365    A68 (expr_stack_limit) = A68 (stack_end) - A68 (storage_overhead);
 366    if (OPTION_REGRESSION_TEST (&A68_JOB)) {
 367      init_rng (1);
 368    } else {
 369      genie_init_rng ();
 370    }
 371    io_close_tty_line ();
 372    if (OPTION_TRACE (&A68_JOB)) {
 373      ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "genie: frame stack %uk, expression stack %uk, heap %uk, handles %uk\n", A68 (frame_stack_size) / KILOBYTE, A68 (expr_stack_size) / KILOBYTE, A68 (heap_size) / KILOBYTE, A68 (handle_pool_size) / KILOBYTE) >= 0);
 374      WRITE (A68_STDOUT, A68 (output_line));
 375    }
 376    install_signal_handlers ();
 377    set_default_event_procedure (&A68 (on_gc_event));
 378    A68 (do_confirm_exit) = A68_TRUE;
 379  #if defined (BUILD_PARALLEL_CLAUSE)
 380    ASSERT (pthread_mutex_init (&A68_PAR (unit_sema), NULL) == 0);
 381  #endif
 382  // Dive into the program.
 383    if (setjmp (A68 (genie_exit_label)) == 0) {
 384      NODE_T *p = SUB (TOP_NODE (&A68_JOB));
 385  // If we are to stop in the monitor, set a breakpoint on the first unit.
 386      if (OPTION_DEBUG (&A68_JOB)) {
 387        change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_TEMPORARY_MASK, A68_TRUE);
 388        WRITE (A68_STDOUT, "Execution begins ...");
 389      }
 390      errno = 0;
 391      A68 (ret_code) = 0;
 392      A68 (global_level) = INT_MAX;
 393      A68_GLOBALS = 0;
 394      get_global_level (p);
 395      A68_FP = A68 (frame_start);
 396      A68_SP = A68 (stack_start);
 397      FRAME_DYNAMIC_LINK (A68_FP) = 0;
 398      FRAME_DNS (A68_FP) = 0;
 399      FRAME_STATIC_LINK (A68_FP) = 0;
 400      FRAME_NUMBER (A68_FP) = 0;
 401      FRAME_TREE (A68_FP) = (NODE_T *) p;
 402      FRAME_LEXICAL_LEVEL (A68_FP) = LEX_LEVEL (p);
 403      FRAME_PARAMETER_LEVEL (A68_FP) = LEX_LEVEL (p);
 404      FRAME_PARAMETERS (A68_FP) = A68_FP;
 405      initialise_frame (p);
 406      genie_init_heap (p);
 407      genie_init_transput (TOP_NODE (&A68_JOB));
 408      A68 (cputime_0) = seconds ();
 409      A68_GC (sema) = 0;
 410  // Here we go ...
 411      A68 (in_execution) = A68_TRUE;
 412      A68 (f_entry) = TOP_NODE (&A68_JOB);
 413  #if defined (BUILD_UNIX)
 414      (void) a68_alarm (INTERRUPT_INTERVAL);
 415  #endif
 416      if (OPTION_TRACE (&A68_JOB)) {
 417        WIS (TOP_NODE (&A68_JOB));
 418      }
 419      (void) genie_enclosed (TOP_NODE (&A68_JOB));
 420    } else {
 421  // Here we have jumped out of the interpreter. What happened?.
 422      if (OPTION_DEBUG (&A68_JOB)) {
 423        WRITE (A68_STDOUT, "Execution discontinued");
 424      }
 425      if (A68 (ret_code) == A68_RERUN) {
 426        diagnostics_to_terminal (TOP_LINE (&A68_JOB), A68_RUNTIME_ERROR);
 427        genie (compile_plugin);
 428      } else if (A68 (ret_code) == A68_RUNTIME_ERROR) {
 429        if (OPTION_BACKTRACE (&A68_JOB)) {
 430          int printed = 0;
 431          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\nStack backtrace") >= 0);
 432          WRITE (A68_STDOUT, A68 (output_line));
 433          stack_dump (A68_STDOUT, A68_FP, 16, &printed);
 434          WRITE (A68_STDOUT, NEWLINE_STRING);
 435        }
 436        if (FILE_LISTING_OPENED (&A68_JOB)) {
 437          int printed = 0;
 438          ASSERT (a68_bufprt (A68 (output_line), SNPRINTF_SIZE, "\nStack backtrace") >= 0);
 439          WRITE (FILE_LISTING_FD (&A68_JOB), A68 (output_line));
 440          stack_dump (FILE_LISTING_FD (&A68_JOB), A68_FP, 32, &printed);
 441        }
 442      }
 443    }
 444    A68 (in_execution) = A68_FALSE;
 445  }
 446  
 447  //! @brief Shows line where 'p' is at and draws a '-' beneath the position.
 448  
 449  void where_in_source (FILE_T f, NODE_T * p)
 450  {
 451    write_source_line (f, LINE (INFO (p)), p, A68_NO_DIAGNOSTICS);
 452  }
 453  
 454  // Since Algol 68 can pass procedures as parameters, we use static links rather
 455  // than a display.
 456  
 457  //! @brief Initialise PROC and OP identities.
 458  
 459  void genie_init_proc_op (NODE_T * p, NODE_T ** seq, int *count)
 460  {
 461    for (; p != NO_NODE; FORWARD (p)) {
 462      switch (ATTRIBUTE (p)) {
 463      case OP_SYMBOL:
 464      case PROC_SYMBOL:
 465      case OPERATOR_PLAN:
 466      case DECLARER: {
 467          break;
 468        }
 469      case DEFINING_IDENTIFIER:
 470      case DEFINING_OPERATOR: {
 471  // Store position so we need not search again.
 472          NODE_T *save = *seq;
 473          (*seq) = p;
 474          SEQUENCE (*seq) = save;
 475          (*count)++;
 476          return;
 477        }
 478      default: {
 479          genie_init_proc_op (SUB (p), seq, count);
 480          break;
 481        }
 482      }
 483    }
 484  }
 485  
 486  //! @brief Initialise PROC and OP identity declarations.
 487  
 488  void genie_find_proc_op (NODE_T * p, int *count)
 489  {
 490    for (; p != NO_NODE; FORWARD (p)) {
 491      if (GINFO (p) != NO_GINFO && IS_NEW_LEXICAL_LEVEL (GINFO (p))) {
 492  // Don't enter a new lexical level - it will have its own initialisation.
 493        return;
 494      } else if (IS (p, PROCEDURE_DECLARATION) || IS (p, BRIEF_OPERATOR_DECLARATION)) {
 495        genie_init_proc_op (SUB (p), &(SEQUENCE (TABLE (p))), count);
 496        return;
 497      } else {
 498        genie_find_proc_op (SUB (p), count);
 499      }
 500    }
 501  }
 502  
 503  //! @brief Initialise stack frame.
 504  
 505  void initialise_frame (NODE_T * p)
 506  {
 507    if (INITIALISE_ANON (TABLE (p))) {
 508      TAG_T *_a_;
 509      INITIALISE_ANON (TABLE (p)) = A68_FALSE;
 510      for (_a_ = ANONYMOUS (TABLE (p)); _a_ != NO_TAG; FORWARD (_a_)) {
 511        if (PRIO (_a_) == ROUTINE_TEXT) {
 512          int youngest = YOUNGEST_ENVIRON (TAX (NODE (_a_)));
 513          A68_PROCEDURE *_z_ = (A68_PROCEDURE *) (FRAME_OBJECT (OFFSET (_a_)));
 514          STATUS (_z_) = INIT_MASK;
 515          NODE (&(BODY (_z_))) = NODE (_a_);
 516          if (youngest > 0) {
 517            STATIC_LINK_FOR_FRAME (ENVIRON (_z_), 1 + youngest);
 518          } else {
 519            ENVIRON (_z_) = 0;
 520          }
 521          LOCALE (_z_) = NO_HANDLE;
 522          MOID (_z_) = MOID (_a_);
 523          INITIALISE_ANON (TABLE (p)) = A68_TRUE;
 524        } else if (PRIO (_a_) == FORMAT_TEXT) {
 525          int youngest = YOUNGEST_ENVIRON (TAX (NODE (_a_)));
 526          A68_FORMAT *_z_ = (A68_FORMAT *) (FRAME_OBJECT (OFFSET (_a_)));
 527          STATUS (_z_) = INIT_MASK;
 528          BODY (_z_) = NODE (_a_);
 529          if (youngest > 0) {
 530            STATIC_LINK_FOR_FRAME (ENVIRON (_z_), 1 + youngest);
 531          } else {
 532            ENVIRON (_z_) = 0;
 533          }
 534          INITIALISE_ANON (TABLE (p)) = A68_TRUE;
 535        }
 536      }
 537    }
 538    if (PROC_OPS (TABLE (p))) {
 539      NODE_T *_q_;
 540      if (SEQUENCE (TABLE (p)) == NO_NODE) {
 541        int count = 0;
 542        genie_find_proc_op (p, &count);
 543        PROC_OPS (TABLE (p)) = (BOOL_T) (count > 0);
 544      }
 545      for (_q_ = SEQUENCE (TABLE (p)); _q_ != NO_NODE; _q_ = SEQUENCE (_q_)) {
 546        NODE_T *u = NEXT_NEXT (_q_);
 547        if (IS (u, ROUTINE_TEXT)) {
 548          NODE_T *src = SOURCE (&(GPROP (u)));
 549          *(A68_PROCEDURE *) FRAME_OBJECT (OFFSET (TAX (_q_))) = *(A68_PROCEDURE *) (FRAME_OBJECT (OFFSET (TAX (src))));
 550        } else if ((IS (u, UNIT) && IS (SUB (u), ROUTINE_TEXT))) {
 551          NODE_T *src = SOURCE (&(GPROP (SUB (u))));
 552          *(A68_PROCEDURE *) FRAME_OBJECT (OFFSET (TAX (_q_))) = *(A68_PROCEDURE *) (FRAME_OBJECT (OFFSET (TAX (src))));
 553        }
 554      }
 555    }
 556    INITIALISE_FRAME (TABLE (p)) = (BOOL_T) (INITIALISE_ANON (TABLE (p)) || PROC_OPS (TABLE (p)));
 557  }
 558  
 559  //! @brief Whether item at "w" of mode "q" is initialised.
 560  
 561  void genie_check_initialisation (NODE_T * p, BYTE_T * w, MOID_T * q)
 562  {
 563    switch (SHORT_ID (q)) {
 564    case REF_SYMBOL: {
 565        A68_REF *z = (A68_REF *) w;
 566        CHECK_INIT (p, INITIALISED (z), q);
 567        return;
 568      }
 569    case PROC_SYMBOL: {
 570        A68_PROCEDURE *z = (A68_PROCEDURE *) w;
 571        CHECK_INIT (p, INITIALISED (z), q);
 572        return;
 573      }
 574    case MODE_INT: {
 575        A68_INT *z = (A68_INT *) w;
 576        CHECK_INIT (p, INITIALISED (z), q);
 577        return;
 578      }
 579    case MODE_REAL: {
 580        A68_REAL *z = (A68_REAL *) w;
 581        CHECK_INIT (p, INITIALISED (z), q);
 582        return;
 583      }
 584    case MODE_COMPLEX: {
 585        A68_REAL *r = (A68_REAL *) w;
 586        A68_REAL *i = (A68_REAL *) (w + SIZE_ALIGNED (A68_REAL));
 587        CHECK_INIT (p, INITIALISED (r), q);
 588        CHECK_INIT (p, INITIALISED (i), q);
 589        return;
 590      }
 591  #if (A68_LEVEL >= 3)
 592    case MODE_LONG_INT:
 593    case MODE_LONG_REAL:
 594    case MODE_LONG_BITS: {
 595        A68_DOUBLE *z = (A68_DOUBLE *) w;
 596        CHECK_INIT (p, INITIALISED (z), q);
 597        return;
 598      }
 599    case MODE_LONG_COMPLEX: {
 600        A68_LONG_REAL *r = (A68_LONG_REAL *) w;
 601        A68_LONG_REAL *i = (A68_LONG_REAL *) (w + SIZE_ALIGNED (A68_LONG_REAL));
 602        CHECK_INIT (p, INITIALISED (r), q);
 603        CHECK_INIT (p, INITIALISED (i), q);
 604        return;
 605      }
 606    case MODE_LONG_LONG_INT:
 607    case MODE_LONG_LONG_REAL:
 608    case MODE_LONG_LONG_BITS: {
 609        MP_T *z = (MP_T *) w;
 610        CHECK_INIT (p, (unt) MP_STATUS (z) & INIT_MASK, q);
 611        return;
 612      }
 613  #else
 614    case MODE_LONG_INT:
 615    case MODE_LONG_LONG_INT:
 616    case MODE_LONG_REAL:
 617    case MODE_LONG_LONG_REAL:
 618    case MODE_LONG_BITS:
 619    case MODE_LONG_LONG_BITS: {
 620        MP_T *z = (MP_T *) w;
 621        CHECK_INIT (p, (unt) MP_STATUS (z) & INIT_MASK, q);
 622        return;
 623      }
 624    case MODE_LONG_COMPLEX: {
 625        MP_T *r = (MP_T *) w;
 626        MP_T *i = (MP_T *) (w + size_mp ());
 627        CHECK_INIT (p, (unt) r[0] & INIT_MASK, q);
 628        CHECK_INIT (p, (unt) i[0] & INIT_MASK, q);
 629        return;
 630      }
 631  #endif
 632    case MODE_LONG_LONG_COMPLEX: {
 633        MP_T *r = (MP_T *) w;
 634        MP_T *i = (MP_T *) (w + size_long_mp ());
 635        CHECK_INIT (p, (unt) r[0] & INIT_MASK, q);
 636        CHECK_INIT (p, (unt) i[0] & INIT_MASK, q);
 637        return;
 638      }
 639    case MODE_BOOL: {
 640        A68_BOOL *z = (A68_BOOL *) w;
 641        CHECK_INIT (p, INITIALISED (z), q);
 642        return;
 643      }
 644    case MODE_CHAR: {
 645        A68_CHAR *z = (A68_CHAR *) w;
 646        CHECK_INIT (p, INITIALISED (z), q);
 647        return;
 648      }
 649    case MODE_BITS: {
 650        A68_BITS *z = (A68_BITS *) w;
 651        CHECK_INIT (p, INITIALISED (z), q);
 652        return;
 653      }
 654    case MODE_BYTES: {
 655        A68_BYTES *z = (A68_BYTES *) w;
 656        CHECK_INIT (p, INITIALISED (z), q);
 657        return;
 658      }
 659    case MODE_LONG_BYTES: {
 660        A68_LONG_BYTES *z = (A68_LONG_BYTES *) w;
 661        CHECK_INIT (p, INITIALISED (z), q);
 662        return;
 663      }
 664    case MODE_FILE: {
 665        A68_FILE *z = (A68_FILE *) w;
 666        CHECK_INIT (p, INITIALISED (z), q);
 667        return;
 668      }
 669    case MODE_FORMAT: {
 670        A68_FORMAT *z = (A68_FORMAT *) w;
 671        CHECK_INIT (p, INITIALISED (z), q);
 672        return;
 673      }
 674    case MODE_PIPE: {
 675        A68_REF *pipe_read = (A68_REF *) w;
 676        A68_REF *pipe_write = (A68_REF *) (w + A68_REF_SIZE);
 677        A68_INT *pid = (A68_INT *) (w + 2 * A68_REF_SIZE);
 678        CHECK_INIT (p, INITIALISED (pipe_read), q);
 679        CHECK_INIT (p, INITIALISED (pipe_write), q);
 680        CHECK_INIT (p, INITIALISED (pid), q);
 681        return;
 682      }
 683    case MODE_SOUND: {
 684        A68_SOUND *z = (A68_SOUND *) w;
 685        CHECK_INIT (p, INITIALISED (z), q);
 686        return;
 687      }
 688    }
 689  }
 690  
 691  //! @brief Propagator_name.
 692  
 693  char *propagator_name (const PROP_PROC * p)
 694  {
 695    if (p == genie_and_function) {
 696      return "genie_and_function";
 697    }
 698    if (p == genie_assertion) {
 699      return "genie_assertion";
 700    }
 701    if (p == genie_assignation) {
 702      return "genie_assignation";
 703    }
 704    if (p == genie_assignation_constant) {
 705      return "genie_assignation_constant";
 706    }
 707    if (p == genie_call) {
 708      return "genie_call";
 709    }
 710    if (p == genie_cast) {
 711      return "genie_cast";
 712    }
 713    if (p == (PROP_PROC *) genie_closed) {
 714      return "genie_closed";
 715    }
 716    if (p == genie_coercion) {
 717      return "genie_coercion";
 718    }
 719    if (p == genie_collateral) {
 720      return "genie_collateral";
 721    }
 722    if (p == genie_column_function) {
 723      return "genie_column_function";
 724    }
 725    if (p == (PROP_PROC *) genie_conditional) {
 726      return "genie_conditional";
 727    }
 728    if (p == genie_constant) {
 729      return "genie_constant";
 730    }
 731    if (p == genie_denotation) {
 732      return "genie_denotation";
 733    }
 734    if (p == genie_deproceduring) {
 735      return "genie_deproceduring";
 736    }
 737    if (p == genie_dereference_frame_identifier) {
 738      return "genie_dereference_frame_identifier";
 739    }
 740    if (p == genie_dereference_selection_name_quick) {
 741      return "genie_dereference_selection_name_quick";
 742    }
 743    if (p == genie_dereference_slice_name_quick) {
 744      return "genie_dereference_slice_name_quick";
 745    }
 746    if (p == genie_dereferencing) {
 747      return "genie_dereferencing";
 748    }
 749    if (p == genie_dereferencing_quick) {
 750      return "genie_dereferencing_quick";
 751    }
 752    if (p == genie_diagonal_function) {
 753      return "genie_diagonal_function";
 754    }
 755    if (p == genie_dyadic) {
 756      return "genie_dyadic";
 757    }
 758    if (p == genie_dyadic_quick) {
 759      return "genie_dyadic_quick";
 760    }
 761    if (p == (PROP_PROC *) genie_enclosed) {
 762      return "genie_enclosed";
 763    }
 764    if (p == genie_format_text) {
 765      return "genie_format_text";
 766    }
 767    if (p == genie_formula) {
 768      return "genie_formula";
 769    }
 770    if (p == genie_generator) {
 771      return "genie_generator";
 772    }
 773    if (p == genie_identifier) {
 774      return "genie_identifier";
 775    }
 776    if (p == genie_identifier_standenv) {
 777      return "genie_identifier_standenv";
 778    }
 779    if (p == genie_identifier_standenv_proc) {
 780      return "genie_identifier_standenv_proc";
 781    }
 782    if (p == genie_identity_relation) {
 783      return "genie_identity_relation";
 784    }
 785    if (p == (PROP_PROC *) genie_int_case) {
 786      return "genie_int_case";
 787    }
 788    if (p == genie_field_selection) {
 789      return "genie_field_selection";
 790    }
 791    if (p == genie_frame_identifier) {
 792      return "genie_frame_identifier";
 793    }
 794    if (p == (PROP_PROC *) genie_loop) {
 795      return "genie_loop";
 796    }
 797    if (p == genie_monadic) {
 798      return "genie_monadic";
 799    }
 800    if (p == genie_nihil) {
 801      return "genie_nihil";
 802    }
 803    if (p == genie_or_function) {
 804      return "genie_or_function";
 805    }
 806  #if defined (BUILD_PARALLEL_CLAUSE)
 807    if (p == genie_parallel) {
 808      return "genie_parallel";
 809    }
 810  #endif
 811    if (p == genie_routine_text) {
 812      return "genie_routine_text";
 813    }
 814    if (p == genie_row_function) {
 815      return "genie_row_function";
 816    }
 817    if (p == genie_rowing) {
 818      return "genie_rowing";
 819    }
 820    if (p == genie_rowing_ref_row_of_row) {
 821      return "genie_rowing_ref_row_of_row";
 822    }
 823    if (p == genie_rowing_ref_row_row) {
 824      return "genie_rowing_ref_row_row";
 825    }
 826    if (p == genie_rowing_row_of_row) {
 827      return "genie_rowing_row_of_row";
 828    }
 829    if (p == genie_rowing_row_row) {
 830      return "genie_rowing_row_row";
 831    }
 832    if (p == genie_selection) {
 833      return "genie_selection";
 834    }
 835    if (p == genie_selection_name_quick) {
 836      return "genie_selection_name_quick";
 837    }
 838    if (p == genie_selection_value_quick) {
 839      return "genie_selection_value_quick";
 840    }
 841    if (p == genie_skip) {
 842      return "genie_skip";
 843    }
 844    if (p == genie_slice) {
 845      return "genie_slice";
 846    }
 847    if (p == genie_slice_name_quick) {
 848      return "genie_slice_name_quick";
 849    }
 850    if (p == genie_transpose_function) {
 851      return "genie_transpose_function";
 852    }
 853    if (p == genie_unit) {
 854      return "genie_unit";
 855    }
 856    if (p == (PROP_PROC *) genie_united_case) {
 857      return "genie_united_case";
 858    }
 859    if (p == genie_uniting) {
 860      return "genie_uniting";
 861    }
 862    if (p == genie_voiding) {
 863      return "genie_voiding";
 864    }
 865    if (p == genie_voiding_assignation) {
 866      return "genie_voiding_assignation";
 867    }
 868    if (p == genie_voiding_assignation_constant) {
 869      return "genie_voiding_assignation_constant";
 870    }
 871    if (p == genie_widen) {
 872      return "genie_widen";
 873    }
 874    if (p == genie_widen_int_to_real) {
 875      return "genie_widen_int_to_real";
 876    }
 877    return NO_TEXT;
 878  }