plugin-gen.c

     
   1  //! @file plugin-gen.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  //! Plugin compiler generator routines.
  25  
  26  #include "a68g.h"
  27  #include "a68g-prelude.h"
  28  #include "a68g-optimiser.h"
  29  #include "a68g-plugin.h"
  30  #include "a68g-parser.h"
  31  
  32  //! @brief Compile code clause.
  33  
  34  void embed_code_clause (NODE_T * p, FILE_T out)
  35  {
  36    for (; p != NO_NODE; FORWARD (p)) {
  37      if (IS (p, ROW_CHAR_DENOTATION)) {
  38        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s\n", NSYMBOL (p)));
  39      }
  40      embed_code_clause (SUB (p), out);
  41    }
  42  }
  43  
  44  //! @brief Compile push.
  45  
  46  void gen_push (NODE_T * p, FILE_T out)
  47  {
  48    if (primitive_mode (MOID (p))) {
  49      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "PUSH_VALUE (p, "));
  50      inline_unit (p, out, L_YIELD);
  51      undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ", %s);\n", inline_mode (MOID (p))));
  52    } else if (basic_mode (MOID (p))) {
  53      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "MOVE ((void *) STACK_TOP, (void *) "));
  54      inline_unit (p, out, L_YIELD);
  55      undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ", %d);\n", SIZE (MOID (p))));
  56      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP += %d;\n", SIZE (MOID (p))));
  57    } else {
  58      ABEND (A68_TRUE, ERROR_INTERNAL_CONSISTENCY, moid_to_string (MOID (p), 80, NO_NODE));
  59    }
  60  }
  61  
  62  //! @brief Compile assign (C source to C destination).
  63  
  64  void gen_assign (NODE_T * p, FILE_T out, char *dst)
  65  {
  66    if (primitive_mode (MOID (p))) {
  67      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "_STATUS_ (%s) = INIT_MASK;\n", dst));
  68      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "_VALUE_ (%s) = ", dst));
  69      inline_unit (p, out, L_YIELD);
  70      undent (out, ";\n");
  71    } else if (basic_mode (MOID (p))) {
  72      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "MOVE ((void *) %s, (void *) ", dst));
  73      inline_unit (p, out, L_YIELD);
  74      undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ", %d);\n", SIZE (MOID (p))));
  75    } else {
  76      ABEND (A68_TRUE, ERROR_INTERNAL_CONSISTENCY, moid_to_string (MOID (p), 80, NO_NODE));
  77    }
  78  }
  79  
  80  //! @brief Compile denotation.
  81  
  82  char *gen_denotation (NODE_T * p, FILE_T out, int compose_fun)
  83  {
  84    if (primitive_mode (MOID (p))) {
  85      if (compose_fun == A68_MAKE_FUNCTION) {
  86        return compile_denotation (p, out);
  87      } else {
  88        static char fn[NAME_SIZE];
  89        comment_source (p, out);
  90        (void) make_name (fn, moid_with_name ("", MOID (p), "_denotation"), "", NUMBER (p));
  91        A68_OPT (root_idf) = NO_DEC;
  92        inline_unit (p, out, L_DECLARE);
  93        print_declarations (out, A68_OPT (root_idf));
  94        inline_unit (p, out, L_EXECUTE);
  95        if (primitive_mode (MOID (p))) {
  96          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "PUSH_VALUE (p, "));
  97          inline_unit (p, out, L_YIELD);
  98          undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ", %s);\n", inline_mode (MOID (p))));
  99        } else {
 100          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "PUSH (p, "));
 101          inline_unit (p, out, L_YIELD);
 102          undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ", %d);\n", SIZE (MOID (p))));
 103        }
 104        return fn;
 105      }
 106    } else {
 107      return NO_TEXT;
 108    }
 109  }
 110  
 111  //! @brief Compile cast.
 112  
 113  char *gen_cast (NODE_T * p, FILE_T out, int compose_fun)
 114  {
 115    if (compose_fun == A68_MAKE_FUNCTION) {
 116      return compile_cast (p, out);
 117    } else if (basic_unit (p)) {
 118      static char fn[NAME_SIZE];
 119      comment_source (p, out);
 120      (void) make_name (fn, moid_with_name ("", MOID (p), "_cast"), "", NUMBER (p));
 121      A68_OPT (root_idf) = NO_DEC;
 122      inline_unit (NEXT_SUB (p), out, L_DECLARE);
 123      print_declarations (out, A68_OPT (root_idf));
 124      inline_unit (NEXT_SUB (p), out, L_EXECUTE);
 125      gen_push (NEXT_SUB (p), out);
 126      return fn;
 127    } else {
 128      return NO_TEXT;
 129    }
 130  }
 131  
 132  //! @brief Compile identifier.
 133  
 134  char *gen_identifier (NODE_T * p, FILE_T out, int compose_fun)
 135  {
 136    if (compose_fun == A68_MAKE_FUNCTION) {
 137      return compile_identifier (p, out);
 138    } else if (basic_mode (MOID (p))) {
 139      static char fn[NAME_SIZE];
 140      (void) make_name (fn, moid_with_name ("deref_REF_", MOID (p), "_identifier"), "", NUMBER (p));
 141      comment_source (p, out);
 142      A68_OPT (root_idf) = NO_DEC;
 143      inline_unit (p, out, L_DECLARE);
 144      print_declarations (out, A68_OPT (root_idf));
 145      inline_unit (p, out, L_EXECUTE);
 146      gen_push (p, out);
 147      return fn;
 148    } else {
 149      return NO_TEXT;
 150    }
 151  }
 152  
 153  //! @brief Compile dereference identifier.
 154  
 155  char *gen_dereference_identifier (NODE_T * p, FILE_T out, int compose_fun)
 156  {
 157    if (compose_fun == A68_MAKE_FUNCTION) {
 158      return compile_dereference_identifier (p, out);
 159    } else if (basic_mode (MOID (p))) {
 160      static char fn[NAME_SIZE];
 161      comment_source (p, out);
 162      (void) make_name (fn, moid_with_name ("deref_REF_", MOID (p), "_identifier"), "", NUMBER (p));
 163      A68_OPT (root_idf) = NO_DEC;
 164      inline_unit (p, out, L_DECLARE);
 165      print_declarations (out, A68_OPT (root_idf));
 166      inline_unit (p, out, L_EXECUTE);
 167      gen_push (p, out);
 168      return fn;
 169    } else {
 170      return NO_TEXT;
 171    }
 172  }
 173  
 174  //! @brief Compile slice.
 175  
 176  char *gen_slice (NODE_T * p, FILE_T out, int compose_fun)
 177  {
 178    if (basic_mode (MOID (p)) && basic_unit (p)) {
 179      static char fn[NAME_SIZE];
 180      comment_source (p, out);
 181      (void) make_name (fn, moid_with_name ("", MOID (p), "_slice"), "", NUMBER (p));
 182      if (compose_fun == A68_MAKE_FUNCTION) {
 183        write_fun_prelude (p, out, fn);
 184      }
 185      A68_OPT (root_idf) = NO_DEC;
 186      inline_unit (p, out, L_DECLARE);
 187      print_declarations (out, A68_OPT (root_idf));
 188      inline_unit (p, out, L_EXECUTE);
 189      gen_push (p, out);
 190      if (compose_fun == A68_MAKE_FUNCTION) {
 191        write_fun_postlude (p, out, fn);
 192      }
 193      return fn;
 194    } else {
 195      return NO_TEXT;
 196    }
 197  }
 198  
 199  //! @brief Compile slice.
 200  
 201  char *gen_dereference_slice (NODE_T * p, FILE_T out, int compose_fun)
 202  {
 203    if (basic_mode (MOID (p)) && basic_unit (p)) {
 204      static char fn[NAME_SIZE];
 205      comment_source (p, out);
 206      (void) make_name (fn, moid_with_name ("deref_REF_", MOID (p), "_slice"), "", NUMBER (p));
 207      if (compose_fun == A68_MAKE_FUNCTION) {
 208        write_fun_prelude (p, out, fn);
 209      }
 210      A68_OPT (root_idf) = NO_DEC;
 211      inline_unit (p, out, L_DECLARE);
 212      print_declarations (out, A68_OPT (root_idf));
 213      inline_unit (p, out, L_EXECUTE);
 214      gen_push (p, out);
 215      if (compose_fun == A68_MAKE_FUNCTION) {
 216        write_fun_postlude (p, out, fn);
 217      }
 218      return fn;
 219    } else {
 220      return NO_TEXT;
 221    }
 222  }
 223  
 224  //! @brief Compile selection.
 225  
 226  char *gen_selection (NODE_T * p, FILE_T out, int compose_fun)
 227  {
 228    if (basic_mode (MOID (p)) && basic_unit (p)) {
 229      static char fn[NAME_SIZE];
 230      comment_source (p, out);
 231      (void) make_name (fn, moid_with_name ("", MOID (p), "_select"), "", NUMBER (p));
 232      if (compose_fun == A68_MAKE_FUNCTION) {
 233        write_fun_prelude (p, out, fn);
 234      }
 235      A68_OPT (root_idf) = NO_DEC;
 236      inline_unit (p, out, L_DECLARE);
 237      print_declarations (out, A68_OPT (root_idf));
 238      inline_unit (p, out, L_EXECUTE);
 239      gen_push (p, out);
 240      if (compose_fun == A68_MAKE_FUNCTION) {
 241        write_fun_postlude (p, out, fn);
 242      }
 243      return fn;
 244    } else {
 245      return NO_TEXT;
 246    }
 247  }
 248  
 249  //! @brief Compile selection.
 250  
 251  char *gen_dereference_selection (NODE_T * p, FILE_T out, int compose_fun)
 252  {
 253    if (basic_mode (MOID (p)) && basic_unit (p)) {
 254      static char fn[NAME_SIZE];
 255      comment_source (p, out);
 256      (void) make_name (fn, moid_with_name ("deref_REF_", MOID (p), "_select"), "", NUMBER (p));
 257      if (compose_fun == A68_MAKE_FUNCTION) {
 258        write_fun_prelude (p, out, fn);
 259      }
 260      A68_OPT (root_idf) = NO_DEC;
 261      inline_unit (p, out, L_DECLARE);
 262      print_declarations (out, A68_OPT (root_idf));
 263      inline_unit (p, out, L_EXECUTE);
 264      gen_push (p, out);
 265      if (compose_fun == A68_MAKE_FUNCTION) {
 266        write_fun_postlude (p, out, fn);
 267      }
 268      return fn;
 269    } else {
 270      return NO_TEXT;
 271    }
 272  }
 273  
 274  //! @brief Compile formula.
 275  
 276  char *gen_formula (NODE_T * p, FILE_T out, int compose_fun)
 277  {
 278    if (basic_unit (p)) {
 279      static char fn[NAME_SIZE];
 280      comment_source (p, out);
 281      (void) make_name (fn, moid_with_name ("", MOID (p), "_formula"), "", NUMBER (p));
 282      if (compose_fun == A68_MAKE_FUNCTION) {
 283        write_fun_prelude (p, out, fn);
 284      }
 285      A68_OPT (root_idf) = NO_DEC;
 286      inline_unit (p, out, L_DECLARE);
 287      print_declarations (out, A68_OPT (root_idf));
 288      if (OPTION_COMPILE_CHECK (&A68_JOB) && !constant_unit (p)) {
 289        if (MOID (p) == M_REAL || MOID (p) == M_COMPLEX) {
 290          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "errno = 0;\n"));
 291        }
 292      }
 293      inline_unit (p, out, L_EXECUTE);
 294      gen_push (p, out);
 295      if (OPTION_COMPILE_CHECK (&A68_JOB) && !constant_unit (p)) {
 296        if (MOID (p) == M_REAL) {
 297          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "MATH_RTE (p, errno != 0, M_REAL, NO_TEXT);\n"));
 298        }
 299        if (MOID (p) == M_COMPLEX) {
 300          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "MATH_RTE (p, errno != 0, M_COMPLEX, NO_TEXT);\n"));
 301        }
 302      }
 303      if (compose_fun == A68_MAKE_FUNCTION) {
 304        write_fun_postlude (p, out, fn);
 305      }
 306      return fn;
 307    } else {
 308      return NO_TEXT;
 309    }
 310  }
 311  
 312  //! @brief Compile voiding formula.
 313  
 314  char *gen_voiding_formula (NODE_T * p, FILE_T out, int compose_fun)
 315  {
 316    if (basic_unit (p)) {
 317      static char fn[NAME_SIZE];
 318      char pop[NAME_SIZE];
 319      (void) make_name (pop, PUP, "", NUMBER (p));
 320      comment_source (p, out);
 321      (void) make_name (fn, moid_with_name ("void_", MOID (p), "_formula"), "", NUMBER (p));
 322      if (compose_fun == A68_MAKE_FUNCTION) {
 323        write_fun_prelude (p, out, fn);
 324      }
 325      A68_OPT (root_idf) = NO_DEC;
 326      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
 327      inline_unit (p, out, L_DECLARE);
 328      print_declarations (out, A68_OPT (root_idf));
 329      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
 330      inline_unit (p, out, L_EXECUTE);
 331      indent (out, "(void) (");
 332      inline_unit (p, out, L_YIELD);
 333      undent (out, ");\n");
 334      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 335      if (compose_fun == A68_MAKE_FUNCTION) {
 336        write_fun_postlude (p, out, fn);
 337      }
 338      return fn;
 339    } else {
 340      return NO_TEXT;
 341    }
 342  }
 343  
 344  //! @brief Compile uniting.
 345  
 346  char *gen_uniting (NODE_T * p, FILE_T out, int compose_fun)
 347  {
 348    MOID_T *u = MOID (p), *v = MOID (SUB (p));
 349    NODE_T *q = SUB (p);
 350    if (basic_unit (q) && ATTRIBUTE (v) != UNION_SYMBOL && primitive_mode (v)) {
 351      static char fn[NAME_SIZE];
 352      char pop0[NAME_SIZE];
 353      (void) make_name (pop0, PUP, "0", NUMBER (p));
 354      comment_source (p, out);
 355      (void) make_name (fn, moid_with_name ("", MOID (p), "_unite"), "", NUMBER (p));
 356      if (compose_fun == A68_MAKE_FUNCTION) {
 357        write_fun_prelude (p, out, fn);
 358      }
 359      A68_OPT (root_idf) = NO_DEC;
 360      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop0);
 361      inline_unit (q, out, L_DECLARE);
 362      print_declarations (out, A68_OPT (root_idf));
 363      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop0));
 364      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "PUSH_UNION (_NODE_ (%d), %s);\n", NUMBER (p), internal_mode (v)));
 365      inline_unit (q, out, L_EXECUTE);
 366      gen_push (q, out);
 367      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s + %d;\n", pop0, SIZE (u)));
 368      if (compose_fun == A68_MAKE_FUNCTION) {
 369        write_fun_postlude (p, out, fn);
 370      }
 371      return fn;
 372    } else {
 373      return NO_TEXT;
 374    }
 375  }
 376  
 377  //! @brief Compile deproceduring.
 378  
 379  char *gen_deproceduring (NODE_T * p, FILE_T out, int compose_fun)
 380  {
 381    NODE_T *idf = stems_from (SUB (p), IDENTIFIER);
 382    if (idf == NO_NODE) {
 383      return NO_TEXT;
 384    } else if (!(SUB_MOID (idf) == M_VOID || basic_mode (SUB_MOID (idf)))) {
 385      return NO_TEXT;
 386    } else if (!(CODEX (TAX (idf)) & PROC_DECLARATION_MASK)) {
 387      return NO_TEXT;
 388    } else {
 389      static char fn[NAME_SIZE];
 390      char fun[NAME_SIZE];
 391      (void) make_name (fun, FUN, "", NUMBER (idf));
 392      comment_source (p, out);
 393      (void) make_name (fn, moid_with_name ("", MOID (p), "_deproc"), "", NUMBER (p));
 394      if (compose_fun == A68_MAKE_FUNCTION) {
 395        write_fun_prelude (p, out, fn);
 396      }
 397  // Declare.
 398      A68_OPT (root_idf) = NO_DEC;
 399      (void) add_declaration (&A68_OPT (root_idf), "A68_PROCEDURE", 1, fun);
 400      (void) add_declaration (&A68_OPT (root_idf), "NODE_T", 1, "body");
 401      print_declarations (out, A68_OPT (root_idf));
 402  // Initialise.
 403      get_stack (idf, out, fun, "A68_PROCEDURE");
 404      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "body = SUB (NODE (&BODY (%s)));\n", fun));
 405      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "OPEN_PROC_FRAME (body, ENVIRON (%s));\n", fun));
 406      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "INIT_STATIC_FRAME (body);\n"));
 407  // Execute procedure.
 408      indent (out, "GENIE_UNIT_TRACE (NEXT_NEXT (body));\n");
 409      indent (out, "if (A68_FP == A68_MON (finish_frame_pointer)) {\n");
 410      A68_OPT (indentation)++;
 411      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_INTERRUPT_MASK, A68_TRUE);\n"));
 412      A68_OPT (indentation)--;
 413      indent (out, "}\n");
 414      indent (out, "CLOSE_FRAME;\n");
 415      if (compose_fun == A68_MAKE_FUNCTION) {
 416        write_fun_postlude (p, out, fn);
 417      }
 418      return fn;
 419    }
 420  }
 421  
 422  //! @brief Compile deproceduring.
 423  
 424  char *gen_voiding_deproceduring (NODE_T * p, FILE_T out, int compose_fun)
 425  {
 426    NODE_T *idf = stems_from (SUB_SUB (p), IDENTIFIER);
 427    if (idf == NO_NODE) {
 428      return NO_TEXT;
 429    } else if (!(SUB_MOID (idf) == M_VOID || basic_mode (SUB_MOID (idf)))) {
 430      return NO_TEXT;
 431    } else if (!(CODEX (TAX (idf)) & PROC_DECLARATION_MASK)) {
 432      return NO_TEXT;
 433    } else {
 434      static char fn[NAME_SIZE];
 435      char fun[NAME_SIZE], pop[NAME_SIZE];
 436      (void) make_name (fun, FUN, "", NUMBER (idf));
 437      (void) make_name (pop, PUP, "", NUMBER (p));
 438      comment_source (p, out);
 439      (void) make_name (fn, moid_with_name ("void_", MOID (p), "_deproc"), "", NUMBER (p));
 440      if (compose_fun == A68_MAKE_FUNCTION) {
 441        write_fun_prelude (p, out, fn);
 442      }
 443  // Declare.
 444      A68_OPT (root_idf) = NO_DEC;
 445      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
 446      (void) add_declaration (&A68_OPT (root_idf), "A68_PROCEDURE", 1, fun);
 447      (void) add_declaration (&A68_OPT (root_idf), "NODE_T", 1, "body");
 448      print_declarations (out, A68_OPT (root_idf));
 449  // Initialise.
 450      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
 451  //  if (compose_fun != A68_MAKE_NOTHING) {
 452  //  }
 453      get_stack (idf, out, fun, "A68_PROCEDURE");
 454      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "body = SUB (NODE (&BODY (%s)));\n", fun));
 455      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "OPEN_PROC_FRAME (body, ENVIRON (%s));\n", fun));
 456      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "INIT_STATIC_FRAME (body);\n"));
 457  // Execute procedure.
 458      indent (out, "GENIE_UNIT_TRACE (NEXT_NEXT (body));\n");
 459      indent (out, "if (A68_FP == A68_MON (finish_frame_pointer)) {\n");
 460      A68_OPT (indentation)++;
 461      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_INTERRUPT_MASK, A68_TRUE);\n"));
 462      A68_OPT (indentation)--;
 463      indent (out, "}\n");
 464      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 465      indent (out, "CLOSE_FRAME;\n");
 466      if (compose_fun == A68_MAKE_FUNCTION) {
 467        write_fun_postlude (p, out, fn);
 468      }
 469      return fn;
 470    }
 471  }
 472  
 473  //! @brief Compile call.
 474  
 475  char *gen_call (NODE_T * p, FILE_T out, int compose_fun)
 476  {
 477    NODE_T *proc = SUB (p);
 478    NODE_T *args = NEXT (proc);
 479    NODE_T *idf = stems_from (proc, IDENTIFIER);
 480    if (idf == NO_NODE) {
 481      return NO_TEXT;
 482    } else if (!(SUB_MOID (proc) == M_VOID || basic_mode (SUB_MOID (proc)))) {
 483      return NO_TEXT;
 484    } else if (DIM (MOID (proc)) == 0) {
 485      return NO_TEXT;
 486    } else if (A68_STANDENV_PROC (TAX (idf))) {
 487      if (basic_call (p)) {
 488        static char fun[NAME_SIZE];
 489        comment_source (p, out);
 490        (void) make_name (fun, moid_with_name ("", SUB_MOID (proc), "_call"), "", NUMBER (p));
 491        if (compose_fun == A68_MAKE_FUNCTION) {
 492          write_fun_prelude (p, out, fun);
 493        }
 494        A68_OPT (root_idf) = NO_DEC;
 495        inline_unit (p, out, L_DECLARE);
 496        print_declarations (out, A68_OPT (root_idf));
 497        inline_unit (p, out, L_EXECUTE);
 498        gen_push (p, out);
 499        if (compose_fun == A68_MAKE_FUNCTION) {
 500          write_fun_postlude (p, out, fun);
 501        }
 502        return fun;
 503      } else {
 504        return NO_TEXT;
 505      }
 506    } else if (!(CODEX (TAX (idf)) & PROC_DECLARATION_MASK)) {
 507      return NO_TEXT;
 508    } else if (DIM (PARTIAL_PROC (GINFO (proc))) != 0) {
 509      return NO_TEXT;
 510    } else if (!basic_argument (args)) {
 511      return NO_TEXT;
 512    } else {
 513      static char fun[NAME_SIZE];
 514      char body[NAME_SIZE], pop[NAME_SIZE];
 515  // Declare.
 516      (void) make_name (body, FUN, "", NUMBER (proc));
 517      (void) make_name (pop, PUP, "", NUMBER (p));
 518      comment_source (p, out);
 519      (void) make_name (fun, moid_with_name ("", SUB_MOID (proc), "_call"), "", NUMBER (p));
 520      if (compose_fun == A68_MAKE_FUNCTION) {
 521        write_fun_prelude (p, out, fun);
 522      }
 523  // Compute arguments.
 524      int size = 0;
 525      A68_OPT (root_idf) = NO_DEC;
 526      inline_arguments (args, out, L_DECLARE, &size);
 527      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
 528      (void) add_declaration (&A68_OPT (root_idf), "A68_PROCEDURE", 1, body);
 529      (void) add_declaration (&A68_OPT (root_idf), "NODE_T", 1, "body");
 530      print_declarations (out, A68_OPT (root_idf));
 531  // Initialise.
 532      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
 533      inline_arguments (args, out, L_INITIALISE, &size);
 534      get_stack (idf, out, body, "A68_PROCEDURE");
 535      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "body = SUB (NODE (&BODY (%s)));\n", body));
 536      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "OPEN_PROC_FRAME (body, ENVIRON (%s));\n", body));
 537      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "INIT_STATIC_FRAME (body);\n"));
 538      size = 0;
 539      inline_arguments (args, out, L_EXECUTE, &size);
 540      size = 0;
 541      inline_arguments (args, out, L_YIELD, &size);
 542  // Execute procedure.
 543      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 544      indent (out, "GENIE_UNIT_TRACE (NEXT_NEXT_NEXT (body));\n");
 545      indent (out, "if (A68_FP == A68_MON (finish_frame_pointer)) {\n");
 546      A68_OPT (indentation)++;
 547      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_INTERRUPT_MASK, A68_TRUE);\n"));
 548      A68_OPT (indentation)--;
 549      indent (out, "}\n");
 550      indent (out, "CLOSE_FRAME;\n");
 551      if (compose_fun == A68_MAKE_FUNCTION) {
 552        write_fun_postlude (p, out, fun);
 553      }
 554      return fun;
 555    }
 556  }
 557  
 558  //! @brief Compile call.
 559  
 560  char *gen_voiding_call (NODE_T * p, FILE_T out, int compose_fun)
 561  {
 562    NODE_T *proc = SUB (stems_from (p, CALL));
 563    NODE_T *args = NEXT (proc);
 564    NODE_T *idf = stems_from (proc, IDENTIFIER);
 565    if (idf == NO_NODE) {
 566      return NO_TEXT;
 567    } else if (!(SUB_MOID (proc) == M_VOID || basic_mode (SUB_MOID (proc)))) {
 568      return NO_TEXT;
 569    } else if (DIM (MOID (proc)) == 0) {
 570      return NO_TEXT;
 571    } else if (A68_STANDENV_PROC (TAX (idf))) {
 572      return NO_TEXT;
 573    } else if (!(CODEX (TAX (idf)) & PROC_DECLARATION_MASK)) {
 574      return NO_TEXT;
 575    } else if (DIM (PARTIAL_PROC (GINFO (proc))) != 0) {
 576      return NO_TEXT;
 577    } else if (!basic_argument (args)) {
 578      return NO_TEXT;
 579    } else {
 580      static char fun[NAME_SIZE];
 581  // Declare.
 582      char body[NAME_SIZE], pop[NAME_SIZE];
 583      (void) make_name (body, FUN, "", NUMBER (proc));
 584      (void) make_name (pop, PUP, "", NUMBER (p));
 585      comment_source (p, out);
 586      (void) make_name (fun, moid_with_name ("void_", SUB_MOID (proc), "_call"), "", NUMBER (p));
 587      if (compose_fun == A68_MAKE_FUNCTION) {
 588        write_fun_prelude (p, out, fun);
 589      }
 590  // Compute arguments.
 591      int size = 0;
 592      A68_OPT (root_idf) = NO_DEC;
 593      inline_arguments (args, out, L_DECLARE, &size);
 594      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
 595      (void) add_declaration (&A68_OPT (root_idf), "A68_PROCEDURE", 1, body);
 596      (void) add_declaration (&A68_OPT (root_idf), "NODE_T", 1, "body");
 597      print_declarations (out, A68_OPT (root_idf));
 598  // Initialise.
 599      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
 600      inline_arguments (args, out, L_INITIALISE, &size);
 601      get_stack (idf, out, body, "A68_PROCEDURE");
 602      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "body = SUB (NODE (&BODY (%s)));\n", body));
 603      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "OPEN_PROC_FRAME (body, ENVIRON (%s));\n", body));
 604      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "INIT_STATIC_FRAME (body);\n"));
 605      size = 0;
 606      inline_arguments (args, out, L_EXECUTE, &size);
 607      size = 0;
 608      inline_arguments (args, out, L_YIELD, &size);
 609  // Execute procedure.
 610      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 611      indent (out, "GENIE_UNIT_TRACE (NEXT_NEXT_NEXT (body));\n");
 612      indent (out, "if (A68_FP == A68_MON (finish_frame_pointer)) {\n");
 613      A68_OPT (indentation)++;
 614      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "change_masks (TOP_NODE (&A68_JOB), BREAKPOINT_INTERRUPT_MASK, A68_TRUE);\n"));
 615      A68_OPT (indentation)--;
 616      indent (out, "}\n");
 617      indent (out, "CLOSE_FRAME;\n");
 618      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 619      if (compose_fun == A68_MAKE_FUNCTION) {
 620        write_fun_postlude (p, out, fun);
 621      }
 622      return fun;
 623    }
 624  }
 625  
 626  //! @brief Compile voiding assignation.
 627  
 628  char *gen_voiding_assignation_selection (NODE_T * p, FILE_T out, int compose_fun)
 629  {
 630    NODE_T *dst = SUB (stems_from (p, ASSIGNATION));
 631    NODE_T *src = NEXT_NEXT (dst);
 632    if (BASIC (dst, SELECTION) && basic_unit (src) && basic_mode_non_row (MOID (dst))) {
 633      NODE_T *field = SUB (stems_from (dst, SELECTION));
 634      NODE_T *sec = NEXT (field);
 635      NODE_T *idf = stems_from (sec, IDENTIFIER);
 636      char sel[NAME_SIZE], ref[NAME_SIZE], pop[NAME_SIZE];
 637      char *field_idf = NSYMBOL (SUB (field));
 638      static char fn[NAME_SIZE];
 639      comment_source (p, out);
 640      (void) make_name (pop, PUP, "", NUMBER (p));
 641      (void) make_name (fn, moid_with_name ("void_", MOID (SUB (p)), "_assign"), "", NUMBER (p));
 642      if (compose_fun == A68_MAKE_FUNCTION) {
 643        write_fun_prelude (p, out, fn);
 644      }
 645  // Declare.
 646      A68_OPT (root_idf) = NO_DEC;
 647      if (signed_in (BOOK_DECL, L_DECLARE, NSYMBOL (idf)) == NO_BOOK) {
 648        (void) make_name (ref, NSYMBOL (idf), "", NUMBER (field));
 649        (void) make_name (sel, SEL, "", NUMBER (field));
 650        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_REF * %s; /* %s */\n", ref, NSYMBOL (idf)));
 651        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s * %s;\n", inline_mode (SUB_MOID (field)), sel));
 652        sign_in (BOOK_DECL, L_DECLARE, NSYMBOL (idf), (void *) field_idf, NUMBER (field));
 653      } else {
 654        int n = NUMBER (signed_in (BOOK_DECL, L_DECLARE, NSYMBOL (idf)));
 655        (void) make_name (ref, NSYMBOL (idf), "", n);
 656        (void) make_name (sel, SEL, "", n);
 657      }
 658      inline_unit (src, out, L_DECLARE);
 659      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
 660      print_declarations (out, A68_OPT (root_idf));
 661      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
 662  // Initialise.
 663      if (signed_in (BOOK_DECL, L_EXECUTE, NSYMBOL (idf)) == NO_BOOK) {
 664        get_stack (idf, out, ref, "A68_REF");
 665        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = (%s *) & (ADDRESS (%s)[" A68_LU "]);\n", sel, inline_mode (SUB_MOID (field)), ref, OFFSET_OFF (field)));
 666        sign_in (BOOK_DECL, L_EXECUTE, NSYMBOL (idf), (void *) field_idf, NUMBER (field));
 667      }
 668      inline_unit (src, out, L_EXECUTE);
 669  // Generate.
 670      gen_assign (src, out, sel);
 671      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 672      if (compose_fun == A68_MAKE_FUNCTION) {
 673        write_fun_postlude (p, out, fn);
 674      }
 675      return fn;
 676    } else {
 677      return NO_TEXT;
 678    }
 679  }
 680  
 681  //! @brief Compile voiding assignation.
 682  
 683  char *gen_voiding_assignation_slice (NODE_T * p, FILE_T out, int compose_fun)
 684  {
 685    NODE_T *dst = SUB (stems_from (p, ASSIGNATION));
 686    NODE_T *src = NEXT_NEXT (dst);
 687    NODE_T *slice = stems_from (SUB (dst), SLICE);
 688    NODE_T *prim = SUB (slice);
 689    MOID_T *mode = SUB_MOID (dst);
 690    MOID_T *row_mode = DEFLEX (MOID (prim));
 691    if (IS (row_mode, REF_SYMBOL) && basic_slice (slice) && basic_unit (src) && basic_mode_non_row (MOID (src))) {
 692      NODE_T *indx = NEXT (prim);
 693      char *symbol = NSYMBOL (SUB (prim));
 694      char drf[NAME_SIZE], idf[NAME_SIZE], arr[NAME_SIZE], tup[NAME_SIZE], elm[NAME_SIZE], pop[NAME_SIZE];
 695      static char fn[NAME_SIZE];
 696      comment_source (p, out);
 697      (void) make_name (pop, PUP, "", NUMBER (p));
 698      (void) make_name (fn, moid_with_name ("void_", MOID (SUB (p)), "_assign"), "", NUMBER (p));
 699      if (compose_fun == A68_MAKE_FUNCTION) {
 700        write_fun_prelude (p, out, fn);
 701      }
 702  // Declare.
 703      A68_OPT (root_idf) = NO_DEC;
 704      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
 705      if (signed_in (BOOK_DECL, L_DECLARE, symbol) == NO_BOOK) {
 706        (void) make_name (idf, symbol, "", NUMBER (prim));
 707        (void) make_name (arr, ARR, "", NUMBER (prim));
 708        (void) make_name (tup, TUP, "", NUMBER (prim));
 709        (void) make_name (elm, ELM, "", NUMBER (prim));
 710        (void) make_name (drf, DRF, "", NUMBER (prim));
 711        (void) add_declaration (&A68_OPT (root_idf), "A68_REF", 1, idf);
 712        (void) add_declaration (&A68_OPT (root_idf), "A68_REF", 0, elm);
 713        (void) add_declaration (&A68_OPT (root_idf), "A68_ARRAY", 1, arr);
 714        (void) add_declaration (&A68_OPT (root_idf), "A68_TUPLE", 1, tup);
 715        (void) add_declaration (&A68_OPT (root_idf), inline_mode (mode), 1, drf);
 716        sign_in (BOOK_DECL, L_DECLARE, symbol, (void *) indx, NUMBER (prim));
 717      } else {
 718        int n = NUMBER (signed_in (BOOK_DECL, L_EXECUTE, symbol));
 719        (void) make_name (idf, symbol, "", n);
 720        (void) make_name (arr, ARR, "", n);
 721        (void) make_name (tup, TUP, "", n);
 722        (void) make_name (elm, ELM, "", n);
 723        (void) make_name (drf, DRF, "", n);
 724      }
 725      INT_T k = 0;
 726      inline_indexer (indx, out, L_DECLARE, &k, NO_TEXT);
 727      inline_unit (src, out, L_DECLARE);
 728      print_declarations (out, A68_OPT (root_idf));
 729  // Initialise.
 730      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
 731      if (signed_in (BOOK_DECL, L_EXECUTE, symbol) == NO_BOOK) {
 732        NODE_T *pidf = stems_from (prim, IDENTIFIER);
 733        get_stack (pidf, out, idf, "A68_REF");
 734        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "GET_DESCRIPTOR (%s, %s, DEREF (A68_ROW, %s));\n", arr, tup, idf));
 735        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = ARRAY (%s);\n", elm, arr));
 736        sign_in (BOOK_DECL, L_EXECUTE, NSYMBOL (p), (void *) indx, NUMBER (prim));
 737      }
 738      k = 0;
 739      inline_indexer (indx, out, L_EXECUTE, &k, NO_TEXT);
 740      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "OFFSET (& %s) += ROW_ELEMENT (%s, ", elm, arr));
 741      k = 0;
 742      inline_indexer (indx, out, L_YIELD, &k, tup);
 743      undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ");\n"));
 744      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = DEREF (%s, & %s);\n", drf, inline_mode (mode), elm));
 745      inline_unit (src, out, L_EXECUTE);
 746  // Generate.
 747      gen_assign (src, out, drf);
 748      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 749      if (compose_fun == A68_MAKE_FUNCTION) {
 750        write_fun_postlude (p, out, fn);
 751      }
 752      return fn;
 753    } else {
 754      return NO_TEXT;
 755    }
 756  }
 757  
 758  //! @brief Compile voiding assignation.
 759  
 760  char *gen_voiding_assignation_identifier (NODE_T * p, FILE_T out, int compose_fun)
 761  {
 762    NODE_T *dst = SUB (stems_from (p, ASSIGNATION));
 763    NODE_T *src = NEXT_NEXT (dst);
 764    if (BASIC (dst, IDENTIFIER) && basic_unit (src) && basic_mode_non_row (MOID (src))) {
 765      static char fn[NAME_SIZE];
 766      char idf[NAME_SIZE], pop[NAME_SIZE];
 767      NODE_T *q = stems_from (dst, IDENTIFIER);
 768  // Declare.
 769      (void) make_name (pop, PUP, "", NUMBER (p));
 770      comment_source (p, out);
 771      (void) make_name (fn, moid_with_name ("void_", MOID (SUB (p)), "_assign"), "", NUMBER (p));
 772      if (compose_fun == A68_MAKE_FUNCTION) {
 773        write_fun_prelude (p, out, fn);
 774      }
 775      A68_OPT (root_idf) = NO_DEC;
 776      if (signed_in (BOOK_DEREF, L_DECLARE, NSYMBOL (q)) == NO_BOOK) {
 777        (void) make_name (idf, NSYMBOL (q), "", NUMBER (p));
 778        (void) add_declaration (&A68_OPT (root_idf), inline_mode (SUB_MOID (dst)), 1, idf);
 779        sign_in (BOOK_DEREF, L_DECLARE, NSYMBOL (q), NULL, NUMBER (p));
 780      } else {
 781        (void) make_name (idf, NSYMBOL (q), "", NUMBER (signed_in (BOOK_DEREF, L_DECLARE, NSYMBOL (p))));
 782      }
 783      inline_unit (dst, out, L_DECLARE);
 784      inline_unit (src, out, L_DECLARE);
 785      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
 786      print_declarations (out, A68_OPT (root_idf));
 787  // Initialise.
 788      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
 789      inline_unit (dst, out, L_EXECUTE);
 790      if (signed_in (BOOK_DEREF, L_EXECUTE, NSYMBOL (q)) == NO_BOOK) {
 791        if (BODY (TAX (q)) != NO_TAG) {
 792          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = (%s *) LOCAL_ADDRESS (", idf, inline_mode (SUB_MOID (dst))));
 793          inline_unit (dst, out, L_YIELD);
 794          undent (out, ");\n");
 795          sign_in (BOOK_DEREF, L_EXECUTE, NSYMBOL (q), NULL, NUMBER (p));
 796        } else {
 797          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = DEREF (%s, ", idf, inline_mode (SUB_MOID (dst))));
 798          inline_unit (dst, out, L_YIELD);
 799          undent (out, ");\n");
 800          sign_in (BOOK_DEREF, L_EXECUTE, NSYMBOL (q), NULL, NUMBER (p));
 801        }
 802      }
 803      inline_unit (src, out, L_EXECUTE);
 804      gen_assign (src, out, idf);
 805      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 806      if (compose_fun == A68_MAKE_FUNCTION) {
 807        write_fun_postlude (p, out, fn);
 808      }
 809      return fn;
 810    } else {
 811      return NO_TEXT;
 812    }
 813  }
 814  
 815  //! @brief Compile identity-relation.
 816  
 817  char *gen_identity_relation (NODE_T * p, FILE_T out, int compose_fun)
 818  {
 819  #define GOOD(p) (stems_from (p, IDENTIFIER) != NO_NODE && IS (MOID (stems_from ((p), IDENTIFIER)), REF_SYMBOL))
 820    NODE_T *lhs = SUB (p);
 821    NODE_T *op = NEXT (lhs);
 822    NODE_T *rhs = NEXT (op);
 823    if (GOOD (lhs) && GOOD (rhs)) {
 824      static char fn[NAME_SIZE];
 825      comment_source (p, out);
 826      (void) make_name (fn, moid_with_name ("", MOID (p), "_identity"), "", NUMBER (p));
 827      if (compose_fun == A68_MAKE_FUNCTION) {
 828        write_fun_prelude (p, out, fn);
 829      }
 830      A68_OPT (root_idf) = NO_DEC;
 831      inline_identity_relation (p, out, L_DECLARE);
 832      print_declarations (out, A68_OPT (root_idf));
 833      inline_identity_relation (p, out, L_EXECUTE);
 834      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "PUSH_VALUE (p, "));
 835      inline_identity_relation (p, out, L_YIELD);
 836      undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ", A68_BOOL);\n"));
 837      if (compose_fun == A68_MAKE_FUNCTION) {
 838        write_fun_postlude (p, out, fn);
 839      }
 840      return fn;
 841    } else if (GOOD (lhs) && stems_from (rhs, NIHIL) != NO_NODE) {
 842      static char fn[NAME_SIZE];
 843      comment_source (p, out);
 844      (void) make_name (fn, moid_with_name ("", MOID (p), "_identity"), "", NUMBER (p));
 845      if (compose_fun == A68_MAKE_FUNCTION) {
 846        write_fun_prelude (p, out, fn);
 847      }
 848      A68_OPT (root_idf) = NO_DEC;
 849      inline_identity_relation (p, out, L_DECLARE);
 850      print_declarations (out, A68_OPT (root_idf));
 851      inline_identity_relation (p, out, L_EXECUTE);
 852      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "PUSH_VALUE (p, "));
 853      inline_identity_relation (p, out, L_YIELD);
 854      undentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, ", A68_BOOL);\n"));
 855      if (compose_fun == A68_MAKE_FUNCTION) {
 856        write_fun_postlude (p, out, fn);
 857      }
 858      return fn;
 859    } else {
 860      return NO_TEXT;
 861    }
 862  #undef GOOD
 863  }
 864  
 865  //! @brief Compile closed clause.
 866  
 867  void gen_declaration_list (NODE_T * p, FILE_T out, int *decs, char *pop)
 868  {
 869    for (; p != NO_NODE; FORWARD (p)) {
 870      switch (ATTRIBUTE (p)) {
 871      case MODE_DECLARATION:
 872      case PROCEDURE_DECLARATION:
 873      case BRIEF_OPERATOR_DECLARATION:
 874      case PRIORITY_DECLARATION: {
 875  // No action needed.
 876          (*decs)++;
 877          return;
 878        }
 879      case OPERATOR_DECLARATION: {
 880          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "genie_operator_dec (_NODE_ (%d));", NUMBER (SUB (p))));
 881          inline_comment_source (p, out);
 882          undent (out, NEWLINE_STRING);
 883          (*decs)++;
 884          break;
 885        }
 886      case IDENTITY_DECLARATION: {
 887          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "genie_identity_dec (_NODE_ (%d));", NUMBER (SUB (p))));
 888          inline_comment_source (p, out);
 889          undent (out, NEWLINE_STRING);
 890          (*decs)++;
 891          break;
 892        }
 893      case VARIABLE_DECLARATION: {
 894          char declarer[NAME_SIZE];
 895          (void) make_name (declarer, DEC, "", NUMBER (SUB (p)));
 896          indent (out, "{");
 897          inline_comment_source (p, out);
 898          undent (out, NEWLINE_STRING);
 899          A68_OPT (indentation)++;
 900          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "NODE_T *%s = NO_NODE;\n", declarer));
 901          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "genie_variable_dec (_NODE_ (%d), &%s, A68_SP);\n", NUMBER (SUB (p)), declarer));
 902          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 903          A68_OPT (indentation)--;
 904          indent (out, "}\n");
 905          (*decs)++;
 906          break;
 907        }
 908      case PROCEDURE_VARIABLE_DECLARATION: {
 909          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "genie_proc_variable_dec (_NODE_ (%d));", NUMBER (SUB (p))));
 910          inline_comment_source (p, out);
 911          undent (out, NEWLINE_STRING);
 912          indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 913          (*decs)++;
 914          break;
 915        }
 916      default: {
 917          gen_declaration_list (SUB (p), out, decs, pop);
 918          break;
 919        }
 920      }
 921    }
 922  }
 923  
 924  //! @brief Compile closed clause.
 925  
 926  void gen_serial_clause (NODE_T * p, FILE_T out, NODE_T ** last, int *units, int *decs, char *pop, int compose_fun)
 927  {
 928    for (; p != NO_NODE && A68_OPT (code_errors) == 0; FORWARD (p)) {
 929      if (compose_fun == A68_MAKE_OTHERS) {
 930        if (IS (p, UNIT)) {
 931          (*units)++;
 932        }
 933        if (IS (p, DECLARATION_LIST)) {
 934          (*decs)++;
 935        }
 936        if (IS (p, UNIT) || IS (p, DECLARATION_LIST)) {
 937          if (gen_unit (p, out, A68_MAKE_FUNCTION) == NO_TEXT) {
 938            if (IS (p, UNIT) && IS (SUB (p), TERTIARY)) {
 939              gen_units (SUB_SUB (p), out);
 940            } else {
 941              gen_units (SUB (p), out);
 942            }
 943          } else if (SUB (p) != NO_NODE && GINFO (SUB (p)) != NO_GINFO && COMPILE_NODE (GINFO (SUB (p))) > 0) {
 944            COMPILE_NODE (GINFO (p)) = COMPILE_NODE (GINFO (SUB (p)));
 945            a68_free (COMPILE_NAME (GINFO (p)));
 946            COMPILE_NAME (GINFO (p)) = new_string (COMPILE_NAME (GINFO (SUB (p))), NO_TEXT);
 947          }
 948          return;
 949        } else {
 950          gen_serial_clause (SUB (p), out, last, units, decs, pop, compose_fun);
 951        }
 952      } else
 953        switch (ATTRIBUTE (p)) {
 954        case UNIT: {
 955            (*last) = p;
 956            CODE_EXECUTE (p);
 957            inline_comment_source (p, out);
 958            undent (out, NEWLINE_STRING);
 959            (*units)++;
 960            return;
 961          }
 962        case SEMI_SYMBOL: {
 963            if (IS (*last, UNIT) && MOID (*last) == M_VOID) {
 964              break;
 965            } else if (IS (*last, DECLARATION_LIST)) {
 966              break;
 967            } else {
 968              indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
 969            }
 970            break;
 971          }
 972        case DECLARATION_LIST: {
 973            (*last) = p;
 974            gen_declaration_list (SUB (p), out, decs, pop);
 975            break;
 976          }
 977        default: {
 978            gen_serial_clause (SUB (p), out, last, units, decs, pop, compose_fun);
 979            break;
 980          }
 981        }
 982    }
 983  }
 984  
 985  //! @brief Embed serial clause.
 986  
 987  void embed_serial_clause (NODE_T * p, FILE_T out, char *pop)
 988  {
 989    NODE_T *last = NO_NODE;
 990    int units = 0, decs = 0;
 991    indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "OPEN_STATIC_FRAME (_NODE_ (%d));\n", NUMBER (p)));
 992    init_static_frame (out, p);
 993    gen_serial_clause (p, out, &last, &units, &decs, pop, A68_MAKE_FUNCTION);
 994    indent (out, "CLOSE_FRAME;\n");
 995  }
 996  
 997  //! @brief Compile code clause.
 998  
 999  char *gen_code_clause (NODE_T * p, FILE_T out, int compose_fun)
1000  {
1001    static char fn[NAME_SIZE];
1002    comment_source (p, out);
1003    (void) make_name (fn, "code", "", NUMBER (p));
1004    if (compose_fun == A68_MAKE_FUNCTION) {
1005      write_fun_prelude (p, out, fn);
1006    }
1007    embed_code_clause (SUB (p), out);
1008    if (compose_fun == A68_MAKE_FUNCTION) {
1009      (void) make_name (fn, "code", "", NUMBER (p));
1010      write_fun_postlude (p, out, fn);
1011    }
1012    return fn;
1013  }
1014  
1015  //! @brief Compile closed clause.
1016  
1017  char *gen_closed_clause (NODE_T * p, FILE_T out, int compose_fun)
1018  {
1019    NODE_T *sc = NEXT_SUB (p);
1020    if (MOID (p) == M_VOID && LABELS (TABLE (sc)) == NO_TAG) {
1021      static char fn[NAME_SIZE];
1022      char pop[NAME_SIZE];
1023      int units = 0, decs = 0;
1024      NODE_T *last = NO_NODE;
1025      gen_serial_clause (sc, out, &last, &units, &decs, pop, A68_MAKE_OTHERS);
1026      (void) make_name (pop, PUP, "", NUMBER (p));
1027      comment_source (p, out);
1028      (void) make_name (fn, "closed", "", NUMBER (p));
1029      if (compose_fun == A68_MAKE_FUNCTION) {
1030        write_fun_prelude (p, out, fn);
1031      }
1032      A68_OPT (root_idf) = NO_DEC;
1033      (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
1034      print_declarations (out, A68_OPT (root_idf));
1035      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
1036      embed_serial_clause (sc, out, pop);
1037      if (compose_fun == A68_MAKE_FUNCTION) {
1038        (void) make_name (fn, "closed", "", NUMBER (p));
1039        write_fun_postlude (p, out, fn);
1040      }
1041      return fn;
1042    } else {
1043      return NO_TEXT;
1044    }
1045  }
1046  
1047  //! @brief Compile collateral clause.
1048  
1049  char *gen_collateral_clause (NODE_T * p, FILE_T out, int compose_fun)
1050  {
1051    if (basic_unit (p) && IS (MOID (p), STRUCT_SYMBOL)) {
1052      static char fn[NAME_SIZE];
1053      comment_source (p, out);
1054      (void) make_name (fn, "collateral", "", NUMBER (p));
1055      if (compose_fun == A68_MAKE_FUNCTION) {
1056        write_fun_prelude (p, out, fn);
1057      }
1058      A68_OPT (root_idf) = NO_DEC;
1059      inline_collateral_units (NEXT_SUB (p), out, L_DECLARE);
1060      print_declarations (out, A68_OPT (root_idf));
1061      inline_collateral_units (NEXT_SUB (p), out, L_EXECUTE);
1062      inline_collateral_units (NEXT_SUB (p), out, L_YIELD);
1063      if (compose_fun == A68_MAKE_FUNCTION) {
1064        (void) make_name (fn, "collateral", "", NUMBER (p));
1065        write_fun_postlude (p, out, fn);
1066      }
1067      return fn;
1068    } else {
1069      return NO_TEXT;
1070    }
1071  }
1072  
1073  //! @brief Compile conditional clause.
1074  
1075  char *gen_basic_conditional (NODE_T * p, FILE_T out, int compose_fun)
1076  {
1077    static char fn[NAME_SIZE];
1078    NODE_T *q = SUB (p);
1079    if (!(basic_mode (MOID (p)) || MOID (p) == M_VOID)) {
1080      return NO_TEXT;
1081    }
1082    p = q;
1083    if (!basic_conditional (p)) {
1084      return NO_TEXT;
1085    }
1086    comment_source (p, out);
1087    (void) make_name (fn, "conditional", "", NUMBER (q));
1088    if (compose_fun == A68_MAKE_FUNCTION) {
1089      write_fun_prelude (q, out, fn);
1090    }
1091  // Collect declarations.
1092    if (IS (p, IF_PART) || IS (p, OPEN_PART)) {
1093      A68_OPT (root_idf) = NO_DEC;
1094      inline_unit (SUB (NEXT_SUB (p)), out, L_DECLARE);
1095      print_declarations (out, A68_OPT (root_idf));
1096      inline_unit (SUB (NEXT_SUB (p)), out, L_EXECUTE);
1097      indent (out, "if (");
1098      inline_unit (SUB (NEXT_SUB (p)), out, L_YIELD);
1099      undent (out, ") {\n");
1100      A68_OPT (indentation)++;
1101    } else {
1102      ABEND (A68_TRUE, ERROR_INTERNAL_CONSISTENCY, __func__);
1103    }
1104    FORWARD (p);
1105    if (IS (p, THEN_PART) || IS (p, CHOICE)) {
1106      int pop = A68_OPT (cse_pointer);
1107      (void) gen_unit (SUB (NEXT_SUB (p)), out, A68_MAKE_NOTHING);
1108      A68_OPT (indentation)--;
1109      A68_OPT (cse_pointer) = pop;
1110    } else {
1111      ABEND (A68_TRUE, ERROR_INTERNAL_CONSISTENCY, __func__);
1112    }
1113    FORWARD (p);
1114    if (IS (p, ELSE_PART) || IS (p, CHOICE)) {
1115      int pop = A68_OPT (cse_pointer);
1116      indent (out, "} else {\n");
1117      A68_OPT (indentation)++;
1118      (void) gen_unit (SUB (NEXT_SUB (p)), out, A68_MAKE_NOTHING);
1119      A68_OPT (indentation)--;
1120      A68_OPT (cse_pointer) = pop;
1121    }
1122  // Done.
1123    indent (out, "}\n");
1124    if (compose_fun == A68_MAKE_FUNCTION) {
1125      (void) make_name (fn, "conditional", "", NUMBER (q));
1126      write_fun_postlude (q, out, fn);
1127    }
1128    return fn;
1129  }
1130  
1131  //! @brief Compile conditional clause.
1132  
1133  char *gen_conditional_clause (NODE_T * p, FILE_T out, int compose_fun)
1134  {
1135    static char fn[NAME_SIZE];
1136    char pop[NAME_SIZE];
1137    int units = 0, decs = 0;
1138  // We only compile IF basic unit or ELIF basic unit, so we save on opening frames.
1139  // Check worthiness of the clause.
1140    if (MOID (p) != M_VOID) {
1141      return NO_TEXT;
1142    }
1143    NODE_T *q = SUB (p);
1144    while (q != NO_NODE && is_one_of (q, IF_PART, OPEN_PART, ELIF_IF_PART, ELSE_OPEN_PART, STOP)) {
1145      if (!basic_serial (NEXT_SUB (q), 1)) {
1146        return NO_TEXT;
1147      }
1148      FORWARD (q);
1149      while (q != NO_NODE && (IS (q, THEN_PART) || IS (q, ELSE_PART) || IS (q, CHOICE))) {
1150        if (LABELS (TABLE (NEXT_SUB (q))) != NO_TAG) {
1151          return NO_TEXT;
1152        }
1153        FORWARD (q);
1154      }
1155      if (q != NO_NODE && is_one_of (q, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
1156        q = SUB (q);
1157      } else if (q != NO_NODE && is_one_of (q, FI_SYMBOL, CLOSE_SYMBOL, STOP)) {
1158        FORWARD (q);
1159      }
1160    }
1161  // Generate embedded units.
1162    q = SUB (p);
1163    while (q != NO_NODE && is_one_of (q, IF_PART, OPEN_PART, ELIF_IF_PART, ELSE_OPEN_PART, STOP)) {
1164      FORWARD (q);
1165      while (q != NO_NODE && (IS (q, THEN_PART) || IS (q, ELSE_PART) || IS (q, CHOICE))) {
1166        NODE_T *last = NO_NODE;
1167        units = decs = 0;
1168        gen_serial_clause (NEXT_SUB (q), out, &last, &units, &decs, pop, A68_MAKE_OTHERS);
1169        FORWARD (q);
1170      }
1171      if (q != NO_NODE && is_one_of (q, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
1172        q = SUB (q);
1173      } else if (q != NO_NODE && is_one_of (q, FI_SYMBOL, CLOSE_SYMBOL, STOP)) {
1174        FORWARD (q);
1175      }
1176    }
1177  // Prep and Dec.
1178    (void) make_name (fn, "conditional", "", NUMBER (p));
1179    (void) make_name (pop, PUP, "", NUMBER (p));
1180    comment_source (p, out);
1181    if (compose_fun == A68_MAKE_FUNCTION) {
1182      write_fun_prelude (p, out, fn);
1183    }
1184    A68_OPT (root_idf) = NO_DEC;
1185    q = SUB (p);
1186    while (q != NO_NODE && is_one_of (q, IF_PART, OPEN_PART, ELIF_IF_PART, ELSE_OPEN_PART, STOP)) {
1187      inline_unit (SUB (NEXT_SUB (q)), out, L_DECLARE);
1188      FORWARD (q);
1189      while (q != NO_NODE && (IS (q, THEN_PART) || IS (q, ELSE_PART) || IS (q, CHOICE))) {
1190        FORWARD (q);
1191      }
1192      if (q != NO_NODE && is_one_of (q, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
1193        q = SUB (q);
1194      } else if (q != NO_NODE && is_one_of (q, FI_SYMBOL, CLOSE_SYMBOL, STOP)) {
1195        FORWARD (q);
1196      }
1197    }
1198    (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
1199    print_declarations (out, A68_OPT (root_idf));
1200  // Generate the function body.
1201    indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
1202    q = SUB (p);
1203    while (q != NO_NODE && is_one_of (q, IF_PART, OPEN_PART, ELIF_IF_PART, ELSE_OPEN_PART, STOP)) {
1204      inline_unit (SUB (NEXT_SUB (q)), out, L_EXECUTE);
1205      FORWARD (q);
1206      while (q != NO_NODE && (IS (q, THEN_PART) || IS (q, ELSE_PART) || IS (q, CHOICE))) {
1207        FORWARD (q);
1208      }
1209      if (q != NO_NODE && is_one_of (q, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
1210        q = SUB (q);
1211      } else if (q != NO_NODE && is_one_of (q, FI_SYMBOL, CLOSE_SYMBOL, STOP)) {
1212        FORWARD (q);
1213      }
1214    }
1215    q = SUB (p);
1216    while (q != NO_NODE && is_one_of (q, IF_PART, OPEN_PART, ELIF_IF_PART, ELSE_OPEN_PART, STOP)) {
1217      BOOL_T else_part = A68_FALSE;
1218      if (is_one_of (q, IF_PART, OPEN_PART, STOP)) {
1219        indent (out, "if (");
1220      } else {
1221        indent (out, "} else if (");
1222      }
1223      inline_unit (SUB (NEXT_SUB (q)), out, L_YIELD);
1224      undent (out, ") {\n");
1225      FORWARD (q);
1226      while (q != NO_NODE && (IS (q, THEN_PART) || IS (q, ELSE_PART) || IS (q, CHOICE))) {
1227        if (else_part) {
1228          indent (out, "} else {\n");
1229        }
1230        A68_OPT (indentation)++;
1231        embed_serial_clause (NEXT_SUB (q), out, pop);
1232        A68_OPT (indentation)--;
1233        else_part = A68_TRUE;
1234        FORWARD (q);
1235      }
1236      if (q != NO_NODE && is_one_of (q, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
1237        q = SUB (q);
1238      } else if (q != NO_NODE && is_one_of (q, FI_SYMBOL, CLOSE_SYMBOL, STOP)) {
1239        FORWARD (q);
1240      }
1241    }
1242    indent (out, "}\n");
1243    if (compose_fun == A68_MAKE_FUNCTION) {
1244      (void) make_name (fn, "conditional", "", NUMBER (p));
1245      write_fun_postlude (p, out, fn);
1246    }
1247    return fn;
1248  }
1249  
1250  //! @brief Compile unit from integral-case in-part.
1251  
1252  BOOL_T gen_int_case_units (NODE_T * p, FILE_T out, NODE_T * sym, int k, int *count, int compose_fun)
1253  {
1254    if (p == NO_NODE) {
1255      return A68_FALSE;
1256    } else {
1257      if (IS (p, UNIT)) {
1258        if (k == *count) {
1259          if (compose_fun == A68_MAKE_FUNCTION) {
1260            indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "case %d: {\n", k));
1261            A68_OPT (indentation)++;
1262            indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "OPEN_STATIC_FRAME (_NODE_ (%d));\n", NUMBER (sym)));
1263            CODE_EXECUTE (p);
1264            inline_comment_source (p, out);
1265            undent (out, NEWLINE_STRING);
1266            indent (out, "CLOSE_FRAME;\n");
1267            indent (out, "break;\n");
1268            A68_OPT (indentation)--;
1269            indent (out, "}\n");
1270          } else if (compose_fun == A68_MAKE_OTHERS) {
1271            if (gen_unit (p, out, A68_MAKE_FUNCTION) == NO_TEXT) {
1272              if (IS (p, UNIT) && IS (SUB (p), TERTIARY)) {
1273                gen_units (SUB_SUB (p), out);
1274              } else {
1275                gen_units (SUB (p), out);
1276              }
1277            } else if (SUB (p) != NO_NODE && GINFO (SUB (p)) != NO_GINFO && COMPILE_NODE (GINFO (SUB (p))) > 0) {
1278              COMPILE_NODE (GINFO (p)) = COMPILE_NODE (GINFO (SUB (p)));
1279              a68_free (COMPILE_NAME (GINFO (p)));
1280              COMPILE_NAME (GINFO (p)) = new_string (COMPILE_NAME (GINFO (SUB (p))), NO_TEXT);
1281            }
1282          }
1283          return A68_TRUE;
1284        } else {
1285          (*count)++;
1286          return A68_FALSE;
1287        }
1288      } else {
1289        if (gen_int_case_units (SUB (p), out, sym, k, count, compose_fun)) {
1290          return A68_TRUE;
1291        } else {
1292          return gen_int_case_units (NEXT (p), out, sym, k, count, compose_fun);
1293        }
1294      }
1295    }
1296  }
1297  
1298  //! @brief Compile integral-case-clause.
1299  
1300  char *gen_int_case_clause (NODE_T * p, FILE_T out, int compose_fun)
1301  {
1302    static char fn[NAME_SIZE];
1303    char pop[NAME_SIZE];
1304    int units = 0, decs = 0, k = 0, count = 0;
1305  // We only compile CASE basic unit.
1306  // Check worthiness of the clause.
1307    if (MOID (p) != M_VOID) {
1308      return NO_TEXT;
1309    }
1310    NODE_T *q = SUB (p);
1311    if (q != NO_NODE && is_one_of (q, CASE_PART, OPEN_PART, STOP)) {
1312      if (!basic_serial (NEXT_SUB (q), 1)) {
1313        return NO_TEXT;
1314      }
1315      FORWARD (q);
1316    } else {
1317      return NO_TEXT;
1318    }
1319    while (q != NO_NODE && is_one_of (q, CASE_IN_PART, OUT_PART, CHOICE, STOP)) {
1320      if (LABELS (TABLE (NEXT_SUB (q))) != NO_TAG) {
1321        return NO_TEXT;
1322      }
1323      FORWARD (q);
1324    }
1325    if (q != NO_NODE && is_one_of (q, ESAC_SYMBOL, CLOSE_SYMBOL, STOP)) {
1326      FORWARD (q);
1327    } else {
1328      return NO_TEXT;
1329    }
1330  // Generate embedded units.
1331    q = SUB (p);
1332    if (q != NO_NODE && is_one_of (q, CASE_PART, OPEN_PART, STOP)) {
1333      FORWARD (q);
1334      if (q != NO_NODE && is_one_of (q, CASE_IN_PART, CHOICE, STOP)) {
1335        units = decs = 0;
1336        k = 0;
1337        do {
1338          count = 1;
1339          k++;
1340        } while (gen_int_case_units (NEXT_SUB (q), out, NO_NODE, k, &count, A68_MAKE_OTHERS));
1341        FORWARD (q);
1342      }
1343      if (q != NO_NODE && is_one_of (q, OUT_PART, CHOICE, STOP)) {
1344        NODE_T *last = NO_NODE;
1345        units = decs = 0;
1346        gen_serial_clause (NEXT_SUB (q), out, &last, &units, &decs, pop, A68_MAKE_OTHERS);
1347        FORWARD (q);
1348      }
1349    }
1350  // Prep and Dec.
1351    (void) make_name (pop, PUP, "", NUMBER (p));
1352    comment_source (p, out);
1353    (void) make_name (fn, "case", "", NUMBER (p));
1354    if (compose_fun == A68_MAKE_FUNCTION) {
1355      write_fun_prelude (p, out, fn);
1356    }
1357    A68_OPT (root_idf) = NO_DEC;
1358    q = SUB (p);
1359    inline_unit (SUB (NEXT_SUB (q)), out, L_DECLARE);
1360    (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
1361    print_declarations (out, A68_OPT (root_idf));
1362  // Generate the function body.
1363    indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
1364    q = SUB (p);
1365    inline_unit (SUB (NEXT_SUB (q)), out, L_EXECUTE);
1366    indent (out, "switch (");
1367    inline_unit (SUB (NEXT_SUB (q)), out, L_YIELD);
1368    undent (out, ") {\n");
1369    A68_OPT (indentation)++;
1370    FORWARD (q);
1371    k = 0;
1372    do {
1373      count = 1;
1374      k++;
1375    } while (gen_int_case_units (NEXT_SUB (q), out, SUB (q), k, &count, A68_MAKE_FUNCTION));
1376    FORWARD (q);
1377    if (q != NO_NODE && is_one_of (q, OUT_PART, CHOICE, STOP)) {
1378      indent (out, "default: {\n");
1379      A68_OPT (indentation)++;
1380      embed_serial_clause (NEXT_SUB (q), out, pop);
1381      indent (out, "break;\n");
1382      A68_OPT (indentation)--;
1383      indent (out, "}\n");
1384    }
1385    A68_OPT (indentation)--;
1386    indent (out, "}\n");
1387    if (compose_fun == A68_MAKE_FUNCTION) {
1388      (void) make_name (fn, "case", "", NUMBER (p));
1389      write_fun_postlude (p, out, fn);
1390    }
1391    return fn;
1392  }
1393  
1394  //! @brief Compile loop clause.
1395  
1396  char *gen_loop_clause (NODE_T * p, FILE_T out, int compose_fun)
1397  {
1398    NODE_T *for_part = NO_NODE, *from_part = NO_NODE, *by_part = NO_NODE, *to_part = NO_NODE, *downto_part = NO_NODE, *while_part = NO_NODE, *sc;
1399    static char fn[NAME_SIZE];
1400    char idf[NAME_SIZE], z[NAME_SIZE], pop[NAME_SIZE];
1401    NODE_T *q = SUB (p);
1402  // FOR identifier.
1403    if (IS (q, FOR_PART)) {
1404      for_part = NEXT_SUB (q);
1405      FORWARD (q);
1406    }
1407  // FROM unit.
1408    if (IS (p, FROM_PART)) {
1409      from_part = NEXT_SUB (q);
1410      if (!basic_unit (from_part)) {
1411        return NO_TEXT;
1412      }
1413      FORWARD (q);
1414    }
1415  // BY unit.
1416    if (IS (q, BY_PART)) {
1417      by_part = NEXT_SUB (q);
1418      if (!basic_unit (by_part)) {
1419        return NO_TEXT;
1420      }
1421      FORWARD (q);
1422    }
1423  // TO unit, DOWNTO unit.
1424    if (IS (q, TO_PART)) {
1425      if (IS (SUB (q), TO_SYMBOL)) {
1426        to_part = NEXT_SUB (q);
1427        if (!basic_unit (to_part)) {
1428          return NO_TEXT;
1429        }
1430      } else if (IS (SUB (q), DOWNTO_SYMBOL)) {
1431        downto_part = NEXT_SUB (q);
1432        if (!basic_unit (downto_part)) {
1433          return NO_TEXT;
1434        }
1435      }
1436      FORWARD (q);
1437    }
1438  // WHILE DO OD is not yet supported.
1439    if (IS (q, WHILE_PART)) {
1440      return NO_TEXT;
1441    }
1442  // DO UNTIL OD is not yet supported.
1443    if (IS (q, DO_PART) || IS (q, ALT_DO_PART)) {
1444      sc = q = NEXT_SUB (q);
1445      if (IS (q, SERIAL_CLAUSE)) {
1446        FORWARD (q);
1447      }
1448      if (q != NO_NODE && IS (q, UNTIL_PART)) {
1449        return NO_TEXT;
1450      }
1451    } else {
1452      return NO_TEXT;
1453    }
1454    if (LABELS (TABLE (sc)) != NO_TAG) {
1455      return NO_TEXT;
1456    }
1457  // Loop clause is compiled.
1458    int units = 0, decs = 0;
1459    NODE_T *last = NO_NODE;
1460    gen_serial_clause (sc, out, &last, &units, &decs, pop, A68_MAKE_OTHERS);
1461    BOOL_T gc = (decs > 0);
1462    comment_source (p, out);
1463    (void) make_name (fn, "loop", "", NUMBER (p));
1464    if (compose_fun == A68_MAKE_FUNCTION) {
1465      write_fun_prelude (p, out, fn);
1466    }
1467    A68_OPT (root_idf) = NO_DEC;
1468    (void) make_name (idf, "k", "", NUMBER (p));
1469    (void) add_declaration (&A68_OPT (root_idf), "INT_T", 0, idf);
1470    if (for_part != NO_NODE) {
1471      (void) make_name (z, "z", "", NUMBER (p));
1472      (void) add_declaration (&A68_OPT (root_idf), "A68_INT", 1, z);
1473    }
1474    if (from_part != NO_NODE) {
1475      inline_unit (from_part, out, L_DECLARE);
1476    }
1477    if (by_part != NO_NODE) {
1478      inline_unit (by_part, out, L_DECLARE);
1479    }
1480    if (to_part != NO_NODE) {
1481      inline_unit (to_part, out, L_DECLARE);
1482    }
1483    if (downto_part != NO_NODE) {
1484      inline_unit (downto_part, out, L_DECLARE);
1485    }
1486    if (while_part != NO_NODE) {
1487      inline_unit (SUB (NEXT_SUB (while_part)), out, L_DECLARE);
1488    }
1489    (void) make_name (pop, PUP, "", NUMBER (p));
1490    (void) add_declaration (&A68_OPT (root_idf), "ADDR_T", 0, pop);
1491    print_declarations (out, A68_OPT (root_idf));
1492    indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = A68_SP;\n", pop));
1493    if (from_part != NO_NODE) {
1494      inline_unit (from_part, out, L_EXECUTE);
1495    }
1496    if (by_part != NO_NODE) {
1497      inline_unit (by_part, out, L_EXECUTE);
1498    }
1499    if (to_part != NO_NODE) {
1500      inline_unit (to_part, out, L_EXECUTE);
1501    }
1502    if (downto_part != NO_NODE) {
1503      inline_unit (downto_part, out, L_EXECUTE);
1504    }
1505    if (while_part != NO_NODE) {
1506      inline_unit (SUB (NEXT_SUB (while_part)), out, L_EXECUTE);
1507    }
1508    indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "OPEN_STATIC_FRAME (_NODE_ (%d));\n", NUMBER (sc)));
1509    init_static_frame (out, sc);
1510    if (for_part != NO_NODE) {
1511      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "%s = (A68_INT *) (FRAME_OBJECT (OFFSET (TAX (_NODE_ (%d)))));\n", z, NUMBER (for_part)));
1512    }
1513  // The loop in C.
1514  // Initialisation.
1515    indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "for (%s = ", idf));
1516    if (from_part == NO_NODE) {
1517      undent (out, "1");
1518    } else {
1519      inline_unit (from_part, out, L_YIELD);
1520    }
1521    undent (out, "; ");
1522  // Condition.
1523    if (to_part == NO_NODE && downto_part == NO_NODE && while_part == NO_NODE) {
1524      undent (out, "A68_TRUE");
1525    } else {
1526      undent (out, idf);
1527      if (to_part != NO_NODE) {
1528        undent (out, " <= ");
1529      } else if (downto_part != NO_NODE) {
1530        undent (out, " >= ");
1531      }
1532      inline_unit (to_part, out, L_YIELD);
1533    }
1534    undent (out, "; ");
1535  // Increment.
1536    if (by_part == NO_NODE) {
1537      undent (out, idf);
1538      if (to_part != NO_NODE) {
1539        undent (out, " ++");
1540      } else if (downto_part != NO_NODE) {
1541        undent (out, " --");
1542      } else {
1543        undent (out, " ++");
1544      }
1545    } else {
1546      undent (out, idf);
1547      if (to_part != NO_NODE) {
1548        undent (out, " += ");
1549      } else if (downto_part != NO_NODE) {
1550        undent (out, " -= ");
1551      } else {
1552        undent (out, " += ");
1553      }
1554      inline_unit (by_part, out, L_YIELD);
1555    }
1556    undent (out, ") {\n");
1557    A68_OPT (indentation)++;
1558    if (gc) {
1559      indent (out, "// genie_preemptive_gc_heap (p);\n");
1560    }
1561    if (for_part != NO_NODE) {
1562      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "_STATUS_ (%s) = INIT_MASK;\n", z));
1563      indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "_VALUE_ (%s) = %s;\n", z, idf));
1564    }
1565    units = decs = 0;
1566    gen_serial_clause (sc, out, &last, &units, &decs, pop, A68_MAKE_FUNCTION);
1567  // Re-initialise if necessary.
1568    BOOL_T need_reinit = (BOOL_T) (AP_INCREMENT (TABLE (sc)) > 0 || need_initialise_frame (sc));
1569    if (need_reinit) {
1570      indent (out, "if (");
1571      if (to_part == NO_NODE && downto_part == NO_NODE) {
1572        undent (out, "A68_TRUE");
1573      } else {
1574        undent (out, idf);
1575        if (to_part != NO_NODE) {
1576          undent (out, " < ");
1577        } else if (downto_part != NO_NODE) {
1578          undent (out, " > ");
1579        }
1580        inline_unit (to_part, out, L_YIELD);
1581      }
1582      undent (out, ") {\n");
1583      A68_OPT (indentation)++;
1584      if (AP_INCREMENT (TABLE (sc)) > 0) {
1585  #if (A68_LEVEL >= 3)
1586        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "FRAME_CLEAR (%llu);\n", AP_INCREMENT (TABLE (sc))));
1587  #else
1588        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "FRAME_CLEAR (%u);\n", AP_INCREMENT (TABLE (sc))));
1589  #endif
1590      }
1591      if (need_initialise_frame (sc)) {
1592        indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "initialise_frame (_NODE_ (%d));\n", NUMBER (sc)));
1593      }
1594      A68_OPT (indentation)--;
1595      indent (out, "}\n");
1596    }
1597  // End of loop.
1598    A68_OPT (indentation)--;
1599    indent (out, "}\n");
1600    indent (out, "CLOSE_FRAME;\n");
1601    indentf (out, a68_bufprt (A68 (edit_line), SNPRINTF_SIZE, "A68_SP = %s;\n", pop));
1602    if (compose_fun == A68_MAKE_FUNCTION) {
1603      (void) make_name (fn, "loop", "", NUMBER (p));
1604      write_fun_postlude (p, out, fn);
1605    }
1606    return fn;
1607  }
1608  
1609  //! @brief Optimise units.
1610  
1611  char *gen_unit (NODE_T * p, FILE_T out, int compose_fun)
1612  {
1613  #define COMPILE(p, out, fun, compose_fun) {\
1614    char * fn = (fun) (p, out, compose_fun);\
1615    if (compose_fun == A68_MAKE_FUNCTION && fn != NO_TEXT) {\
1616      ABEND (strlen (fn) >= NAME_SIZE, ERROR_INTERNAL_CONSISTENCY, __func__);\
1617      COMPILE_NAME (GINFO (p)) = new_string (fn, NO_TEXT);\
1618      if (SUB (p) != NO_NODE && COMPILE_NODE (GINFO (SUB (p))) > 0) {\
1619        COMPILE_NODE (GINFO (p)) = COMPILE_NODE (GINFO (SUB (p)));\
1620      } else {\
1621        COMPILE_NODE (GINFO (p)) = NUMBER (p);\
1622      }\
1623      return COMPILE_NAME (GINFO (p));\
1624    } else {\
1625      COMPILE_NAME (GINFO (p)) = NO_TEXT;\
1626      COMPILE_NODE (GINFO (p)) = 0;\
1627      return NO_TEXT;\
1628    }}
1629  
1630    LOW_SYSTEM_STACK_ALERT (p);
1631    if (p == NO_NODE) {
1632      return NO_TEXT;
1633    } else if (COMPILE_NAME (GINFO (p)) != NO_TEXT) {
1634      return NO_TEXT;
1635    } else if (is_one_of (p, UNIT, TERTIARY, SECONDARY, PRIMARY, ENCLOSED_CLAUSE, STOP)) {
1636      COMPILE (SUB (p), out, gen_unit, compose_fun);
1637    }
1638    if (A68_OPT (OPTION_CODE_LEVEL) >= 3) {
1639  // Control structure.
1640      if (IS (p, CLOSED_CLAUSE)) {
1641        COMPILE (p, out, gen_closed_clause, compose_fun);
1642      } else if (IS (p, COLLATERAL_CLAUSE)) {
1643        COMPILE (p, out, gen_collateral_clause, compose_fun);
1644      } else if (IS (p, CONDITIONAL_CLAUSE)) {
1645        char *fn2 = gen_basic_conditional (p, out, compose_fun);
1646        if (compose_fun == A68_MAKE_FUNCTION && fn2 != NO_TEXT) {
1647          ABEND (strlen (fn2) >= NAME_SIZE, ERROR_INTERNAL_CONSISTENCY, __func__);
1648          COMPILE_NAME (GINFO (p)) = new_string (fn2, NO_TEXT);
1649          if (SUB (p) != NO_NODE && COMPILE_NODE (GINFO (SUB (p))) > 0) {
1650            COMPILE_NODE (GINFO (p)) = COMPILE_NODE (GINFO (SUB (p)));
1651          } else {
1652            COMPILE_NODE (GINFO (p)) = NUMBER (p);
1653          }
1654          return COMPILE_NAME (GINFO (p));
1655        } else {
1656          COMPILE (p, out, gen_conditional_clause, compose_fun);
1657        }
1658      } else if (IS (p, CASE_CLAUSE)) {
1659        COMPILE (p, out, gen_int_case_clause, compose_fun);
1660      } else if (IS (p, LOOP_CLAUSE)) {
1661        COMPILE (p, out, gen_loop_clause, compose_fun);
1662      }
1663    }
1664    if (A68_OPT (OPTION_CODE_LEVEL) >= 2) {
1665  // Simple constructions.
1666      if (IS (p, VOIDING) && IS (SUB (p), ASSIGNATION) && stems_from (SUB_SUB (p), IDENTIFIER) != NO_NODE) {
1667        COMPILE (p, out, gen_voiding_assignation_identifier, compose_fun);
1668      } else if (IS (p, VOIDING) && IS (SUB (p), ASSIGNATION) && stems_from (SUB_SUB (p), SLICE) != NO_NODE) {
1669        COMPILE (p, out, gen_voiding_assignation_slice, compose_fun);
1670      } else if (IS (p, VOIDING) && IS (SUB (p), ASSIGNATION) && stems_from (SUB_SUB (p), SELECTION) != NO_NODE) {
1671        COMPILE (p, out, gen_voiding_assignation_selection, compose_fun);
1672      } else if (IS (p, SLICE)) {
1673        COMPILE (p, out, gen_slice, compose_fun);
1674      } else if (IS (p, DEREFERENCING) && stems_from (SUB (p), SLICE) != NO_NODE) {
1675        COMPILE (p, out, gen_dereference_slice, compose_fun);
1676      } else if (IS (p, SELECTION)) {
1677        COMPILE (p, out, gen_selection, compose_fun);
1678      } else if (IS (p, DEREFERENCING) && stems_from (SUB (p), SELECTION) != NO_NODE) {
1679        COMPILE (p, out, gen_dereference_selection, compose_fun);
1680      } else if (IS (p, VOIDING) && IS (SUB (p), FORMULA)) {
1681        COMPILE (SUB (p), out, gen_voiding_formula, compose_fun);
1682      } else if (IS (p, VOIDING) && IS (SUB (p), MONADIC_FORMULA)) {
1683        COMPILE (SUB (p), out, gen_voiding_formula, compose_fun);
1684      } else if (IS (p, DEPROCEDURING)) {
1685        COMPILE (p, out, gen_deproceduring, compose_fun);
1686      } else if (IS (p, VOIDING) && IS (SUB (p), DEPROCEDURING)) {
1687        COMPILE (p, out, gen_voiding_deproceduring, compose_fun);
1688      } else if (IS (p, VOIDING) && IS (SUB (p), CALL)) {
1689        COMPILE (p, out, gen_voiding_call, compose_fun);
1690      } else if (IS (p, IDENTITY_RELATION)) {
1691        COMPILE (p, out, gen_identity_relation, compose_fun);
1692      } else if (IS (p, UNITING)) {
1693        COMPILE (p, out, gen_uniting, compose_fun);
1694      }
1695    }
1696    if (A68_OPT (OPTION_CODE_LEVEL) >= 1) {
1697  // Most basic stuff.
1698      if (IS (p, VOIDING)) {
1699        COMPILE (SUB (p), out, gen_unit, compose_fun);
1700      } else if (IS (p, DENOTATION)) {
1701        COMPILE (p, out, gen_denotation, compose_fun);
1702      } else if (IS (p, CAST)) {
1703        COMPILE (p, out, gen_cast, compose_fun);
1704      } else if (IS (p, IDENTIFIER)) {
1705        COMPILE (p, out, gen_identifier, compose_fun);
1706      } else if (IS (p, DEREFERENCING) && stems_from (SUB (p), IDENTIFIER) != NO_NODE) {
1707        COMPILE (p, out, gen_dereference_identifier, compose_fun);
1708      } else if (IS (p, MONADIC_FORMULA)) {
1709        COMPILE (p, out, gen_formula, compose_fun);
1710      } else if (IS (p, FORMULA)) {
1711        COMPILE (p, out, gen_formula, compose_fun);
1712      } else if (IS (p, CALL)) {
1713        COMPILE (p, out, gen_call, compose_fun);
1714      }
1715    }
1716    if (IS (p, CODE_CLAUSE)) {
1717      COMPILE (p, out, gen_code_clause, compose_fun);
1718    }
1719    return NO_TEXT;
1720  #undef COMPILE
1721  }
1722  
1723  //! @brief Compile unit.
1724  
1725  char *gen_basic (NODE_T * p, FILE_T out)
1726  {
1727  #define COMPILE(p, out, fun) {\
1728    char * fn = (fun) (p, out);\
1729    if (fn != NO_TEXT) {\
1730      ABEND (strlen (fn) >= NAME_SIZE, ERROR_INTERNAL_CONSISTENCY, __func__);\
1731      COMPILE_NAME (GINFO (p)) = new_string (fn, NO_TEXT);\
1732      if (SUB (p) != NO_NODE && COMPILE_NODE (GINFO (SUB (p))) > 0) {\
1733        COMPILE_NODE (GINFO (p)) = COMPILE_NODE (GINFO (SUB (p)));\
1734      } else {\
1735        COMPILE_NODE (GINFO (p)) = NUMBER (p);\
1736      }\
1737      return COMPILE_NAME (GINFO (p));\
1738    } else {\
1739      COMPILE_NAME (GINFO (p)) = NO_TEXT;\
1740      COMPILE_NODE (GINFO (p)) = 0;\
1741      return NO_TEXT;\
1742    }}
1743  
1744    LOW_SYSTEM_STACK_ALERT (p);
1745    if (p == NO_NODE) {
1746      return NO_TEXT;
1747    } else if (COMPILE_NAME (GINFO (p)) != NO_TEXT) {
1748      return NO_TEXT;
1749    } else if (is_one_of (p, UNIT, TERTIARY, SECONDARY, PRIMARY, ENCLOSED_CLAUSE, STOP)) {
1750      COMPILE (SUB (p), out, gen_basic);
1751    }
1752  // Most basic stuff.
1753    if (IS (p, VOIDING)) {
1754      COMPILE (SUB (p), out, gen_basic);
1755    } else if (IS (p, DENOTATION)) {
1756      COMPILE (p, out, compile_denotation);
1757    } else if (IS (p, CAST)) {
1758      COMPILE (p, out, compile_cast);
1759    } else if (IS (p, IDENTIFIER)) {
1760      COMPILE (p, out, compile_identifier);
1761    } else if (IS (p, DEREFERENCING) && stems_from (SUB (p), IDENTIFIER) != NO_NODE) {
1762      COMPILE (p, out, compile_dereference_identifier);
1763    } else if (IS (p, FORMULA)) {
1764      COMPILE (p, out, compile_formula);
1765    } else if (IS (p, CALL)) {
1766      COMPILE (p, out, compile_call);
1767    }
1768    return NO_TEXT;
1769  #undef COMPILE
1770  }
1771  
1772  //! @brief Optimise units.
1773  
1774  void gen_units (NODE_T * p, FILE_T out)
1775  {
1776    for (; p != NO_NODE; FORWARD (p)) {
1777      if (IS (p, UNIT) || IS (p, CODE_CLAUSE)) {
1778        if (gen_unit (p, out, A68_MAKE_FUNCTION) == NO_TEXT) {
1779          gen_units (SUB (p), out);
1780        } else if (SUB (p) != NO_NODE && GINFO (SUB (p)) != NO_GINFO && COMPILE_NODE (GINFO (SUB (p))) > 0) {
1781          COMPILE_NODE (GINFO (p)) = COMPILE_NODE (GINFO (SUB (p)));
1782          COMPILE_NAME (GINFO (p)) = new_string (COMPILE_NAME (GINFO (SUB (p))), NO_TEXT);
1783        }
1784      } else {
1785        gen_units (SUB (p), out);
1786      }
1787    }
1788  }
1789  
1790  //! @brief Compile units.
1791  
1792  void gen_basics (NODE_T * p, FILE_T out)
1793  {
1794    for (; p != NO_NODE; FORWARD (p)) {
1795      if (IS (p, UNIT) || IS (p, CODE_CLAUSE)) {
1796        if (gen_basic (p, out) == NO_TEXT) {
1797          gen_basics (SUB (p), out);
1798        } else if (SUB (p) != NO_NODE && GINFO (SUB (p)) != NO_GINFO && COMPILE_NODE (GINFO (SUB (p))) > 0) {
1799          COMPILE_NODE (GINFO (p)) = COMPILE_NODE (GINFO (SUB (p)));
1800          COMPILE_NAME (GINFO (p)) = new_string (COMPILE_NAME (GINFO (SUB (p))), NO_TEXT);
1801        }
1802      } else {
1803        gen_basics (SUB (p), out);
1804      }
1805    }
1806  }