parser-modes.c

     
   1  //! @file parser-modes.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  //! Mode table management.
  25  
  26  #include "a68g.h"
  27  #include "a68g-postulates.h"
  28  #include "a68g-parser.h"
  29  
  30  // Mode collection, equivalencing and derived modes.
  31  
  32  // Mode service routines.
  33  
  34  //! @brief Count bounds in declarer in tree.
  35  
  36  int count_bounds (NODE_T * p)
  37  {
  38    if (p == NO_NODE) {
  39      return 0;
  40    } else {
  41      if (IS (p, BOUND)) {
  42        return 1 + count_bounds (NEXT (p));
  43      } else {
  44        return count_bounds (NEXT (p)) + count_bounds (SUB (p));
  45      }
  46    }
  47  }
  48  
  49  //! @brief Count number of SHORTs or LONGs.
  50  
  51  int count_sizety (NODE_T * p)
  52  {
  53    if (p == NO_NODE) {
  54      return 0;
  55    } else if (IS (p, LONGETY)) {
  56      return count_sizety (SUB (p)) + count_sizety (NEXT (p));
  57    } else if (IS (p, SHORTETY)) {
  58      return count_sizety (SUB (p)) + count_sizety (NEXT (p));
  59    } else if (IS (p, LONG_SYMBOL)) {
  60      return 1;
  61    } else if (IS (p, SHORT_SYMBOL)) {
  62      return -1;
  63    } else {
  64      return 0;
  65    }
  66  }
  67  
  68  //! @brief Count moids in a pack.
  69  
  70  int count_pack_members (PACK_T * u)
  71  {
  72    int k = 0;
  73    for (; u != NO_PACK; FORWARD (u)) {
  74      k++;
  75    }
  76    return k;
  77  }
  78  
  79  //! @brief Replace a mode by its equivalent mode.
  80  
  81  void resolve_equivalent (MOID_T ** m)
  82  {
  83    while ((*m) != NO_MOID && EQUIVALENT ((*m)) != NO_MOID && (*m) != EQUIVALENT (*m)) {
  84      (*m) = EQUIVALENT (*m);
  85    }
  86  }
  87  
  88  //! @brief Reset moid.
  89  
  90  void reset_moid_tree (NODE_T * p)
  91  {
  92    for (; p != NO_NODE; FORWARD (p)) {
  93      MOID (p) = NO_MOID;
  94      reset_moid_tree (SUB (p));
  95    }
  96  }
  97  
  98  //! @brief Renumber moids.
  99  
 100  void renumber_moids (MOID_T * p, int n)
 101  {
 102    if (p != NO_MOID) {
 103      NUMBER (p) = n;
 104      renumber_moids (NEXT (p), n + 1);
 105    }
 106  }
 107  
 108  //! @brief Register mode in the global mode table, if mode is unique.
 109  
 110  MOID_T *register_extra_mode (MOID_T ** z, MOID_T * u)
 111  {
 112    // If we already know this mode, return the existing entry; otherwise link it in.
 113    for (MOID_T *head = TOP_MOID (&A68_JOB); head != NO_MOID; FORWARD (head)) {
 114      if (prove_moid_equivalence (head, u)) {
 115        return head;
 116      }
 117    }
 118  // Link to chain and exit.
 119    NUMBER (u) = A68 (mode_count)++;
 120    NEXT (u) = (*z);
 121    return *z = u;
 122  }
 123  
 124  //! @brief Add mode "sub" to chain "z".
 125  
 126  MOID_T *add_mode (MOID_T ** z, int att, int dim, NODE_T * node, MOID_T * sub, PACK_T * pack)
 127  {
 128    MOID_T *new_mode = new_moid ();
 129    if (sub == NO_MOID) {
 130      ABEND (att == REF_SYMBOL, ERROR_INTERNAL_CONSISTENCY, __func__);
 131      ABEND (att == FLEX_SYMBOL, ERROR_INTERNAL_CONSISTENCY, __func__);
 132      ABEND (att == ROW_SYMBOL, ERROR_INTERNAL_CONSISTENCY, __func__);
 133    }
 134    USE (new_mode) = A68_FALSE;
 135    SIZE (new_mode) = 0;
 136    ATTRIBUTE (new_mode) = att;
 137    DIM (new_mode) = dim;
 138    NODE (new_mode) = node;
 139    HAS_ROWS (new_mode) = (BOOL_T) (att == ROW_SYMBOL);
 140    SUB (new_mode) = sub;
 141    PACK (new_mode) = pack;
 142    NEXT (new_mode) = NO_MOID;
 143    EQUIVALENT (new_mode) = NO_MOID;
 144    SLICE (new_mode) = NO_MOID;
 145    DEFLEXED (new_mode) = NO_MOID;
 146    NAME (new_mode) = NO_MOID;
 147    MULTIPLE (new_mode) = NO_MOID;
 148    ROWED (new_mode) = NO_MOID;
 149    return register_extra_mode (z, new_mode);
 150  }
 151  
 152  //! @brief Contract a UNION.
 153  
 154  void contract_union (MOID_T * u)
 155  {
 156    for (PACK_T *s = PACK (u); s != NO_PACK; FORWARD (s)) {
 157      PACK_T *t = s;
 158      while (t != NO_PACK) {
 159        if (NEXT (t) != NO_PACK && MOID (NEXT (t)) == MOID (s)) {
 160          MOID (t) = MOID (t);
 161          NEXT (t) = NEXT_NEXT (t);
 162        } else {
 163          FORWARD (t);
 164        }
 165      }
 166    }
 167  }
 168  
 169  //! @brief Absorb UNION pack.
 170  
 171  PACK_T *absorb_union_pack (PACK_T * u)
 172  {
 173    PACK_T *z;
 174    BOOL_T siga;
 175    do {
 176      z = NO_PACK;
 177      siga = A68_FALSE;
 178      for (PACK_T *t = u; t != NO_PACK; FORWARD (t)) {
 179        if (IS (MOID (t), UNION_SYMBOL)) {
 180          siga = A68_TRUE;
 181          for (PACK_T *s = PACK (MOID (t)); s != NO_PACK; FORWARD (s)) {
 182            (void) add_mode_to_pack (&z, MOID (s), NO_TEXT, NODE (s));
 183          }
 184        } else {
 185          (void) add_mode_to_pack (&z, MOID (t), NO_TEXT, NODE (t));
 186        }
 187      }
 188      u = z;
 189    } while (siga);
 190    return z;
 191  }
 192  
 193  //! @brief Add row and its slices to chain, recursively.
 194  
 195  MOID_T *add_row (MOID_T ** p, int dim, MOID_T * sub, NODE_T * n, BOOL_T derivate)
 196  {
 197    MOID_T *q = add_mode (p, ROW_SYMBOL, dim, n, sub, NO_PACK);
 198    DERIVATE (q) |= derivate;
 199    if (dim > 1) {
 200      SLICE (q) = add_row (&NEXT (q), dim - 1, sub, n, derivate);
 201    } else {
 202      SLICE (q) = sub;
 203    }
 204    return q;
 205  }
 206  
 207  //! @brief Add a moid to a pack, maybe with a (field) name.
 208  
 209  void add_mode_to_pack (PACK_T ** p, MOID_T * m, char *text, NODE_T * node)
 210  {
 211    PACK_T *z = new_pack ();
 212    MOID (z) = m;
 213    TEXT (z) = text;
 214    NODE (z) = node;
 215    NEXT (z) = *p;
 216    PREVIOUS (z) = NO_PACK;
 217    if (NEXT (z) != NO_PACK) {
 218      PREVIOUS (NEXT (z)) = z;
 219    }
 220  // Link in chain.
 221    *p = z;
 222  }
 223  
 224  //! @brief Add a moid to a pack, maybe with a (field) name.
 225  
 226  void add_mode_to_pack_end (PACK_T ** p, MOID_T * m, char *text, NODE_T * node)
 227  {
 228    PACK_T *z = new_pack ();
 229    MOID (z) = m;
 230    TEXT (z) = text;
 231    NODE (z) = node;
 232    NEXT (z) = NO_PACK;
 233    if (NEXT (z) != NO_PACK) {
 234      PREVIOUS (NEXT (z)) = z;
 235    }
 236  // Link in chain.
 237    while ((*p) != NO_PACK) {
 238      p = &(NEXT (*p));
 239    }
 240    PREVIOUS (z) = (*p);
 241    (*p) = z;
 242  }
 243  
 244  //! @brief Absorb UNION members.
 245  
 246  void absorb_unions (MOID_T * m)
 247  {
 248  // UNION (A, UNION (B, C)) = UNION (A, B, C) or
 249  // UNION (A, UNION (A, B)) = UNION (A, B).
 250    for (; m != NO_MOID; FORWARD (m)) {
 251      if (IS (m, UNION_SYMBOL)) {
 252        PACK (m) = absorb_union_pack (PACK (m));
 253      }
 254    }
 255  }
 256  
 257  //! @brief Contract UNIONs .
 258  
 259  void contract_unions (MOID_T * m)
 260  {
 261  // UNION (A, B, A) -> UNION (A, B).
 262    for (; m != NO_MOID; FORWARD (m)) {
 263      if (IS (m, UNION_SYMBOL) && EQUIVALENT (m) == NO_MOID) {
 264        contract_union (m);
 265      }
 266    }
 267  }
 268  
 269  // Routines to collect MOIDs from the program text.
 270  
 271  //! @brief Search standard mode in standard environ.
 272  
 273  MOID_T *search_standard_mode (int sizety, NODE_T * indicant)
 274  {
 275    // Search standard mode.
 276    for (MOID_T *p = TOP_MOID (&A68_JOB); p != NO_MOID; FORWARD (p)) {
 277      if (IS (p, STANDARD) && DIM (p) == sizety && NSYMBOL (NODE (p)) == NSYMBOL (indicant)) {
 278        return p;
 279      }
 280    }
 281  // Sanity check
 282  //if (sizety == -2 || sizety == 2) {
 283  //  return NO_MOID;
 284  //}
 285  // Map onto greater precision.
 286    if (sizety < 0) {
 287      return search_standard_mode (sizety + 1, indicant);
 288    } else if (sizety > 0) {
 289      return search_standard_mode (sizety - 1, indicant);
 290    } else {
 291      return NO_MOID;
 292    }
 293  }
 294  
 295  //! @brief Collect mode from STRUCT field.
 296  
 297  void get_mode_from_struct_field (NODE_T * p, PACK_T ** u)
 298  {
 299    if (p != NO_NODE) {
 300      if (IS (p, IDENTIFIER)) {
 301        ATTRIBUTE (p) = FIELD_IDENTIFIER;
 302        (void) add_mode_to_pack (u, NO_MOID, NSYMBOL (p), p);
 303      } else if (IS (p, DECLARER)) {
 304        MOID_T *new_one = get_mode_from_declarer (p);
 305        get_mode_from_struct_field (NEXT (p), u);
 306        for (PACK_T *t = *u; t && MOID (t) == NO_MOID; FORWARD (t)) {
 307          MOID (t) = new_one;
 308          MOID (NODE (t)) = new_one;
 309        }
 310      } else {
 311        get_mode_from_struct_field (NEXT (p), u);
 312        get_mode_from_struct_field (SUB (p), u);
 313      }
 314    }
 315  }
 316  
 317  //! @brief Collect MODE from formal pack.
 318  
 319  void get_mode_from_formal_pack (NODE_T * p, PACK_T ** u)
 320  {
 321    if (p != NO_NODE) {
 322      if (IS (p, DECLARER)) {
 323        get_mode_from_formal_pack (NEXT (p), u);
 324        MOID_T *z = get_mode_from_declarer (p);
 325        (void) add_mode_to_pack (u, z, NO_TEXT, p);
 326      } else {
 327        get_mode_from_formal_pack (NEXT (p), u);
 328        get_mode_from_formal_pack (SUB (p), u);
 329      }
 330    }
 331  }
 332  
 333  //! @brief Collect MODE or VOID from formal UNION pack.
 334  
 335  void get_mode_from_union_pack (NODE_T * p, PACK_T ** u)
 336  {
 337    if (p != NO_NODE) {
 338      if (IS (p, DECLARER) || IS (p, VOID_SYMBOL)) {
 339        get_mode_from_union_pack (NEXT (p), u);
 340        MOID_T *z = get_mode_from_declarer (p);
 341        (void) add_mode_to_pack (u, z, NO_TEXT, p);
 342      } else {
 343        get_mode_from_union_pack (NEXT (p), u);
 344        get_mode_from_union_pack (SUB (p), u);
 345      }
 346    }
 347  }
 348  
 349  //! @brief Collect mode from PROC, OP pack.
 350  
 351  void get_mode_from_routine_pack (NODE_T * p, PACK_T ** u)
 352  {
 353    if (p != NO_NODE) {
 354      if (IS (p, IDENTIFIER)) {
 355        (void) add_mode_to_pack (u, NO_MOID, NO_TEXT, p);
 356      } else if (IS (p, DECLARER)) {
 357        MOID_T *z = get_mode_from_declarer (p);
 358        for (PACK_T *t = *u; t != NO_PACK && MOID (t) == NO_MOID; FORWARD (t)) {
 359          MOID (t) = z;
 360          MOID (NODE (t)) = z;
 361        }
 362        (void) add_mode_to_pack (u, z, NO_TEXT, p);
 363      } else {
 364        get_mode_from_routine_pack (NEXT (p), u);
 365        get_mode_from_routine_pack (SUB (p), u);
 366      }
 367    }
 368  }
 369  
 370  //! @brief Collect MODE from DECLARER.
 371  
 372  MOID_T *get_mode_from_declarer (NODE_T * p)
 373  {
 374    if (p == NO_NODE) {
 375      return NO_MOID;
 376    } else {
 377      if (IS (p, DECLARER)) {
 378        if (MOID (p) != NO_MOID) {
 379          return MOID (p);
 380        } else {
 381          return MOID (p) = get_mode_from_declarer (SUB (p));
 382        }
 383      } else {
 384        if (IS (p, VOID_SYMBOL)) {
 385          MOID (p) = M_VOID;
 386          return MOID (p);
 387        } else if (IS (p, LONGETY)) {
 388          if (whether (p, LONGETY, INDICANT, STOP)) {
 389            int k = count_sizety (SUB (p));
 390            MOID (p) = search_standard_mode (k, NEXT (p));
 391            return MOID (p);
 392          } else {
 393            return NO_MOID;
 394          }
 395        } else if (IS (p, SHORTETY)) {
 396          if (whether (p, SHORTETY, INDICANT, STOP)) {
 397            int k = count_sizety (SUB (p));
 398            MOID (p) = search_standard_mode (k, NEXT (p));
 399            return MOID (p);
 400          } else {
 401            return NO_MOID;
 402          }
 403        } else if (IS (p, INDICANT)) {
 404          MOID_T *q = search_standard_mode (0, p);
 405          if (q != NO_MOID) {
 406            MOID (p) = q;
 407          } else {
 408  // Position of definition tells indicants apart.
 409            TAG_T *y = find_tag_global (TABLE (p), INDICANT, NSYMBOL (p));
 410            if (y == NO_TAG) {
 411              diagnostic (A68_ERROR, p, ERROR_UNDECLARED_TAG_2, NSYMBOL (p));
 412            } else {
 413              MOID (p) = add_mode (&TOP_MOID (&A68_JOB), INDICANT, 0, NODE (y), NO_MOID, NO_PACK);
 414            }
 415          }
 416          return MOID (p);
 417        } else if (IS_REF (p)) {
 418          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 419          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, p, new_one, NO_PACK);
 420          return MOID (p);
 421        } else if (IS_FLEX (p)) {
 422          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 423          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), FLEX_SYMBOL, 0, p, new_one, NO_PACK);
 424          SLICE (MOID (p)) = SLICE (new_one);
 425          return MOID (p);
 426        } else if (IS (p, FORMAL_BOUNDS)) {
 427          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 428          MOID (p) = add_row (&TOP_MOID (&A68_JOB), 1 + count_formal_bounds (SUB (p)), new_one, p, A68_FALSE);
 429          return MOID (p);
 430        } else if (IS (p, BOUNDS)) {
 431          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 432          MOID (p) = add_row (&TOP_MOID (&A68_JOB), count_bounds (SUB (p)), new_one, p, A68_FALSE);
 433          return MOID (p);
 434        } else if (IS (p, STRUCT_SYMBOL)) {
 435          PACK_T *u = NO_PACK;
 436          get_mode_from_struct_field (NEXT (p), &u);
 437          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), STRUCT_SYMBOL, count_pack_members (u), p, NO_MOID, u);
 438          return MOID (p);
 439        } else if (IS (p, UNION_SYMBOL)) {
 440          PACK_T *u = NO_PACK;
 441          get_mode_from_union_pack (NEXT (p), &u);
 442          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), UNION_SYMBOL, count_pack_members (u), p, NO_MOID, u);
 443          return MOID (p);
 444        } else if (IS (p, PROC_SYMBOL)) {
 445          NODE_T *save = p;
 446          PACK_T *u = NO_PACK;
 447          if (IS (NEXT (p), FORMAL_DECLARERS)) {
 448            get_mode_from_formal_pack (SUB_NEXT (p), &u);
 449            FORWARD (p);
 450          }
 451          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 452          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, count_pack_members (u), save, new_one, u);
 453          MOID (save) = MOID (p);
 454          return MOID (p);
 455        } else {
 456          return NO_MOID;
 457        }
 458      }
 459    }
 460  }
 461  
 462  //! @brief Collect MODEs from a routine-text header.
 463  
 464  MOID_T *get_mode_from_routine_text (NODE_T * p)
 465  {
 466    PACK_T *u = NO_PACK;
 467    NODE_T *q = p;
 468    if (IS (p, PARAMETER_PACK)) {
 469      get_mode_from_routine_pack (SUB (p), &u);
 470      FORWARD (p);
 471    }
 472    MOID_T *n = get_mode_from_declarer (p);
 473    return add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, count_pack_members (u), q, n, u);
 474  }
 475  
 476  //! @brief Collect modes from operator-plan.
 477  
 478  MOID_T *get_mode_from_operator (NODE_T * p)
 479  {
 480    PACK_T *u = NO_PACK;
 481    NODE_T *save = p;
 482    if (IS (NEXT (p), FORMAL_DECLARERS)) {
 483      get_mode_from_formal_pack (SUB_NEXT (p), &u);
 484      FORWARD (p);
 485    }
 486    MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 487    MOID (p) = add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, count_pack_members (u), save, new_one, u);
 488    return MOID (p);
 489  }
 490  
 491  //! @brief Collect mode from denotation.
 492  
 493  void get_mode_from_denotation (NODE_T * p, int sizety)
 494  {
 495    if (p != NO_NODE) {
 496      if (IS (p, ROW_CHAR_DENOTATION)) {
 497        if (strlen (NSYMBOL (p)) == 1) {
 498          MOID (p) = M_CHAR;
 499        } else {
 500          MOID (p) = M_ROW_CHAR;
 501        }
 502      } else if (IS (p, TRUE_SYMBOL) || IS (p, FALSE_SYMBOL)) {
 503        MOID (p) = M_BOOL;
 504      } else if (IS (p, INT_DENOTATION)) {
 505        if (sizety == 0) {
 506          MOID (p) = M_INT;
 507        } else if (sizety == 1) {
 508          MOID (p) = M_LONG_INT;
 509        } else if (sizety == 2) {
 510          MOID (p) = M_LONG_LONG_INT;
 511        } else {
 512          MOID (p) = (sizety > 0 ? M_LONG_LONG_INT : M_INT);
 513        }
 514      } else if (IS (p, REAL_DENOTATION)) {
 515        if (sizety == 0) {
 516          MOID (p) = M_REAL;
 517        } else if (sizety == 1) {
 518          MOID (p) = M_LONG_REAL;
 519        } else if (sizety == 2) {
 520          MOID (p) = M_LONG_LONG_REAL;
 521        } else {
 522          MOID (p) = (sizety > 0 ? M_LONG_LONG_REAL : M_REAL);
 523        }
 524      } else if (IS (p, BITS_DENOTATION)) {
 525        if (sizety == 0) {
 526          MOID (p) = M_BITS;
 527        } else if (sizety == 1) {
 528          MOID (p) = M_LONG_BITS;
 529        } else if (sizety == 2) {
 530          MOID (p) = M_LONG_LONG_BITS;
 531        } else {
 532          MOID (p) = (sizety > 0 ? M_LONG_LONG_BITS : M_BITS);
 533        }
 534      } else if (IS (p, LONGETY) || IS (p, SHORTETY)) {
 535        get_mode_from_denotation (NEXT (p), count_sizety (SUB (p)));
 536        MOID (p) = MOID (NEXT (p));
 537      } else if (IS (p, EMPTY_SYMBOL)) {
 538        MOID (p) = M_VOID;
 539      }
 540    }
 541  }
 542  
 543  //! @brief Collect modes from the syntax tree.
 544  
 545  void get_modes_from_tree (NODE_T * p, int attribute)
 546  {
 547    for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) {
 548      if (IS (q, VOID_SYMBOL)) {
 549        MOID (q) = M_VOID;
 550      } else if (IS (q, DECLARER)) {
 551        if (attribute == VARIABLE_DECLARATION) {
 552          MOID_T *new_one = get_mode_from_declarer (q);
 553          MOID (q) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK);
 554        } else {
 555          MOID (q) = get_mode_from_declarer (q);
 556        }
 557      } else if (IS (q, ROUTINE_TEXT)) {
 558        MOID (q) = get_mode_from_routine_text (SUB (q));
 559      } else if (IS (q, OPERATOR_PLAN)) {
 560        MOID (q) = get_mode_from_operator (SUB (q));
 561      } else if (is_one_of (q, LOC_SYMBOL, HEAP_SYMBOL, NEW_SYMBOL, STOP)) {
 562        if (attribute == GENERATOR) {
 563          MOID_T *new_one = get_mode_from_declarer (NEXT (q));
 564          MOID (NEXT (q)) = new_one;
 565          MOID (q) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK);
 566        }
 567      } else {
 568        if (attribute == DENOTATION) {
 569          get_mode_from_denotation (q, 0);
 570        }
 571      }
 572    }
 573    if (attribute != DENOTATION) {
 574      for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) {
 575        if (SUB (q) != NO_NODE) {
 576          get_modes_from_tree (SUB (q), ATTRIBUTE (q));
 577        }
 578      }
 579    }
 580  }
 581  
 582  //! @brief Collect modes from proc variables.
 583  
 584  void get_mode_from_proc_variables (NODE_T * p)
 585  {
 586    if (p != NO_NODE) {
 587      if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
 588        get_mode_from_proc_variables (SUB (p));
 589        get_mode_from_proc_variables (NEXT (p));
 590      } else if (IS (p, QUALIFIER) || IS (p, PROC_SYMBOL) || IS (p, COMMA_SYMBOL)) {
 591        get_mode_from_proc_variables (NEXT (p));
 592      } else if (IS (p, DEFINING_IDENTIFIER)) {
 593        MOID_T *new_one = MOID (NEXT_NEXT (p));
 594        MOID (p) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, p, new_one, NO_PACK);
 595      }
 596    }
 597  }
 598  
 599  //! @brief Collect modes from proc variable declarations.
 600  
 601  void get_mode_from_proc_var_declarations_tree (NODE_T * p)
 602  {
 603    for (; p != NO_NODE; FORWARD (p)) {
 604      get_mode_from_proc_var_declarations_tree (SUB (p));
 605      if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
 606        get_mode_from_proc_variables (p);
 607      }
 608    }
 609  }
 610  
 611  // Various routines to test modes.
 612  
 613  //! @brief Whether a mode declaration refers to self or relates to void.
 614  
 615  BOOL_T is_well_formed (MOID_T * def, MOID_T * z, BOOL_T yin, BOOL_T yang, BOOL_T video)
 616  {
 617    if (z == NO_MOID) {
 618      return A68_FALSE;
 619    } else if (yin && yang) {
 620      return z == M_VOID ? video : A68_TRUE;
 621    } else if (z == M_VOID) {
 622      return video;
 623    } else if (IS (z, STANDARD)) {
 624      return A68_TRUE;
 625    } else if (IS (z, INDICANT)) {
 626      if (def == NO_MOID) {
 627  // Check an applied indicant for relation to VOID.
 628        while (z != NO_MOID) {
 629          z = EQUIVALENT (z);
 630        }
 631        if (z == M_VOID) {
 632          return video;
 633        } else {
 634          return A68_TRUE;
 635        }
 636      } else {
 637        if (z == def || USE (z)) {
 638          return yin && yang;
 639        } else {
 640          USE (z) = A68_TRUE;
 641          BOOL_T wwf = is_well_formed (def, EQUIVALENT (z), yin, yang, video);
 642          USE (z) = A68_FALSE;
 643          return wwf;
 644        }
 645      }
 646    } else if (IS_REF (z)) {
 647      return is_well_formed (def, SUB (z), A68_TRUE, yang, A68_FALSE);
 648    } else if (IS (z, PROC_SYMBOL)) {
 649      return PACK (z) != NO_PACK ? A68_TRUE : is_well_formed (def, SUB (z), A68_TRUE, yang, A68_TRUE);
 650    } else if (IS_ROW (z)) {
 651      return is_well_formed (def, SUB (z), yin, yang, A68_FALSE);
 652    } else if (IS_FLEX (z)) {
 653      return is_well_formed (def, SUB (z), yin, yang, A68_FALSE);
 654    } else if (IS (z, STRUCT_SYMBOL)) {
 655      for (PACK_T *s = PACK (z); s != NO_PACK; FORWARD (s)) {
 656        if (!is_well_formed (def, MOID (s), yin, A68_TRUE, A68_FALSE)) {
 657          return A68_FALSE;
 658        }
 659      }
 660      return A68_TRUE;
 661    } else if (IS (z, UNION_SYMBOL)) {
 662      for (PACK_T *s = PACK (z); s != NO_PACK; FORWARD (s)) {
 663        if (!is_well_formed (def, MOID (s), yin, yang, A68_TRUE)) {
 664          return A68_FALSE;
 665        }
 666      }
 667      return A68_TRUE;
 668    } else {
 669      return A68_FALSE;
 670    }
 671  }
 672  
 673  //! @brief Replace a mode by its equivalent mode (walk chain).
 674  
 675  void resolve_eq_members (MOID_T * q)
 676  {
 677    resolve_equivalent (&SUB (q));
 678    resolve_equivalent (&DEFLEXED (q));
 679    resolve_equivalent (&MULTIPLE (q));
 680    resolve_equivalent (&NAME (q));
 681    resolve_equivalent (&SLICE (q));
 682    resolve_equivalent (&TRIM (q));
 683    resolve_equivalent (&ROWED (q));
 684    for (PACK_T *p = PACK (q); p != NO_PACK; FORWARD (p)) {
 685      resolve_equivalent (&MOID (p));
 686    }
 687  }
 688  
 689  //! @brief Track equivalent tags.
 690  
 691  void resolve_eq_tags (TAG_T * z)
 692  {
 693    for (; z != NO_TAG; FORWARD (z)) {
 694      if (MOID (z) != NO_MOID) {
 695        resolve_equivalent (&MOID (z));
 696      }
 697    }
 698  }
 699  
 700  //! @brief Bind modes in syntax tree.
 701  
 702  void bind_modes (NODE_T * p)
 703  {
 704    for (; p != NO_NODE; FORWARD (p)) {
 705      resolve_equivalent (&MOID (p));
 706      if (SUB (p) != NO_NODE && is_new_lexical_level (p)) {
 707        TABLE_T *s = TABLE (SUB (p));
 708        for (TAG_T *z = INDICANTS (s); z != NO_TAG; FORWARD (z)) {
 709          if (NODE (z) != NO_NODE) {
 710            resolve_equivalent (&MOID (NEXT_NEXT (NODE (z))));
 711            MOID (z) = MOID (NEXT_NEXT (NODE (z)));
 712            MOID (NODE (z)) = MOID (z);
 713          }
 714        }
 715      }
 716      bind_modes (SUB (p));
 717    }
 718  }
 719  
 720  // Routines for calculating subordinates for selections, for instance selection
 721  // from REF STRUCT (A) yields REF A fields and selection from [] STRUCT (A) yields
 722  // [] A fields.
 723  
 724  //! @brief Make name pack.
 725  
 726  void make_name_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p)
 727  {
 728    if (src != NO_PACK) {
 729      make_name_pack (NEXT (src), dst, p);
 730      MOID_T *z = add_mode (p, REF_SYMBOL, 0, NO_NODE, MOID (src), NO_PACK);
 731      (void) add_mode_to_pack (dst, z, TEXT (src), NODE (src));
 732    }
 733  }
 734  
 735  //! @brief Make flex multiple row pack.
 736  
 737  void make_flex_multiple_row_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p, int dim)
 738  {
 739    if (src != NO_PACK) {
 740      make_flex_multiple_row_pack (NEXT (src), dst, p, dim);
 741      MOID_T *z = add_row (p, dim, MOID (src), NO_NODE, A68_FALSE);
 742      z = add_mode (p, FLEX_SYMBOL, 0, NO_NODE, z, NO_PACK);
 743      (void) add_mode_to_pack (dst, z, TEXT (src), NODE (src));
 744    }
 745  }
 746  
 747  //! @brief Make name struct.
 748  
 749  MOID_T *make_name_struct (MOID_T * m, MOID_T ** p)
 750  {
 751    PACK_T *u = NO_PACK;
 752    make_name_pack (PACK (m), &u, p);
 753    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 754  }
 755  
 756  //! @brief Make name row.
 757  
 758  MOID_T *make_name_row (MOID_T * m, MOID_T ** p)
 759  {
 760    if (SLICE (m) != NO_MOID) {
 761      return add_mode (p, REF_SYMBOL, 0, NO_NODE, SLICE (m), NO_PACK);
 762    } else if (SUB (m) != NO_MOID) {
 763      return add_mode (p, REF_SYMBOL, 0, NO_NODE, SUB (m), NO_PACK);
 764    } else {
 765      return NO_MOID;             // weird, FLEX INT or so ...
 766    }
 767  }
 768  
 769  //! @brief Make multiple row pack.
 770  
 771  void make_multiple_row_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p, int dim)
 772  {
 773    if (src != NO_PACK) {
 774      make_multiple_row_pack (NEXT (src), dst, p, dim);
 775      (void) add_mode_to_pack (dst, add_row (p, dim, MOID (src), NO_NODE, A68_FALSE), TEXT (src), NODE (src));
 776    }
 777  }
 778  
 779  //! @brief Make flex multiple struct.
 780  
 781  MOID_T *make_flex_multiple_struct (MOID_T * m, MOID_T ** p, int dim)
 782  {
 783    PACK_T *u = NO_PACK;
 784    make_flex_multiple_row_pack (PACK (m), &u, p, dim);
 785    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 786  }
 787  
 788  //! @brief Make multiple struct.
 789  
 790  MOID_T *make_multiple_struct (MOID_T * m, MOID_T ** p, int dim)
 791  {
 792    PACK_T *u = NO_PACK;
 793    make_multiple_row_pack (PACK (m), &u, p, dim);
 794    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 795  }
 796  
 797  //! @brief Whether mode has row.
 798  
 799  BOOL_T is_mode_has_row (MOID_T * m)
 800  {
 801    if (IS (m, STRUCT_SYMBOL) || IS (m, UNION_SYMBOL)) {
 802      BOOL_T k = A68_FALSE;
 803      for (PACK_T *p = PACK (m); p != NO_PACK && k == A68_FALSE; FORWARD (p)) {
 804        HAS_ROWS (MOID (p)) = is_mode_has_row (MOID (p));
 805        k |= (HAS_ROWS (MOID (p)));
 806      }
 807      return k;
 808    } else {
 809      return (BOOL_T) (HAS_ROWS (m) || IS_ROW (m) || IS_FLEX (m));
 810    }
 811  }
 812  
 813  //! @brief Compute derived modes.
 814  
 815  void compute_derived_modes (MODULE_T * mod)
 816  {
 817    MOID_T *z;
 818    int len = 0, nlen = 1;
 819  // UNION things.
 820    absorb_unions (TOP_MOID (mod));
 821    contract_unions (TOP_MOID (mod));
 822  // The for-statement below prevents an endless loop.
 823    for (int k = 1; k <= 10 && len != nlen; k++) {
 824  // Make deflexed modes.
 825      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 826        if (SUB (z) != NO_MOID) {
 827          if (IS_REF_FLEX (z) && DEFLEXED (SUB_SUB (z)) != NO_MOID) {
 828            DEFLEXED (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB_SUB (z)), NO_PACK);
 829          } else if (IS_REF (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 830            DEFLEXED (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB (z)), NO_PACK);
 831          } else if (IS_ROW (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 832            DEFLEXED (z) = add_mode (&TOP_MOID (mod), ROW_SYMBOL, DIM (z), NODE (z), DEFLEXED (SUB (z)), NO_PACK);
 833          } else if (IS_FLEX (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 834            DEFLEXED (z) = DEFLEXED (SUB (z));
 835          } else if (IS_FLEX (z)) {
 836            DEFLEXED (z) = SUB (z);
 837          } else {
 838            DEFLEXED (z) = z;
 839          }
 840        }
 841      }
 842  // Derived modes for stowed modes.
 843      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 844        if (NAME (z) == NO_MOID && IS_REF (z)) {
 845          if (IS (SUB (z), STRUCT_SYMBOL)) {
 846            NAME (z) = make_name_struct (SUB (z), &TOP_MOID (mod));
 847          } else if (IS_ROW (SUB (z))) {
 848            NAME (z) = make_name_row (SUB (z), &TOP_MOID (mod));
 849          } else if (IS_FLEX (SUB (z)) && SUB_SUB (z) != NO_MOID) {
 850            NAME (z) = make_name_row (SUB_SUB (z), &TOP_MOID (mod));
 851          }
 852        }
 853        if (MULTIPLE (z) != NO_MOID) {
 854          ;
 855        } else if (IS_REF (z)) {
 856          if (MULTIPLE (SUB (z)) != NO_MOID) {
 857            MULTIPLE (z) = make_name_struct (MULTIPLE (SUB (z)), &TOP_MOID (mod));
 858          }
 859        } else if (IS_ROW (z)) {
 860          if (IS (SUB (z), STRUCT_SYMBOL)) {
 861            MULTIPLE (z) = make_multiple_struct (SUB (z), &TOP_MOID (mod), DIM (z));
 862          }
 863        }
 864      }
 865      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 866        if (TRIM (z) == NO_MOID && IS_FLEX (z)) {
 867          TRIM (z) = SUB (z);
 868        }
 869        if (TRIM (z) == NO_MOID && IS_REF_FLEX (z)) {
 870          TRIM (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), SUB_SUB (z), NO_PACK);
 871        }
 872      }
 873  // Fill out stuff for rows, f.i. inverse relations.
 874      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 875        if (IS_ROW (z) && DIM (z) > 0 && SUB (z) != NO_MOID && !DERIVATE (z)) {
 876          (void) add_row (&TOP_MOID (mod), DIM (z) + 1, SUB (z), NODE (z), A68_TRUE);
 877        } else if (IS_REF (z) && IS (SUB (z), ROW_SYMBOL) && !DERIVATE (SUB (z))) {
 878          MOID_T *x = add_row (&TOP_MOID (mod), DIM (SUB (z)) + 1, SUB_SUB (z), NODE (SUB (z)), A68_TRUE);
 879          MOID_T *y = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), x, NO_PACK);
 880          NAME (y) = z;
 881        }
 882      }
 883      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 884        if (IS_ROW (z) && SLICE (z) != NO_MOID) {
 885          ROWED (SLICE (z)) = z;
 886        }
 887        if (IS_REF (z)) {
 888          MOID_T *y = SUB (z);
 889          if (SLICE (y) != NO_MOID && IS_ROW (SLICE (y)) && NAME (z) != NO_MOID) {
 890            ROWED (NAME (z)) = z;
 891          }
 892        }
 893      }
 894      bind_modes (TOP_NODE (mod));
 895      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 896        if (IS (z, INDICANT) && NODE (z) != NO_NODE) {
 897          EQUIVALENT (z) = MOID (NODE (z));
 898        }
 899      }
 900      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 901        resolve_eq_members (z);
 902      }
 903      resolve_eq_tags (INDICANTS (A68_STANDENV));
 904      resolve_eq_tags (IDENTIFIERS (A68_STANDENV));
 905      resolve_eq_tags (OPERATORS (A68_STANDENV));
 906      resolve_equivalent (&M_STRING);
 907      resolve_equivalent (&M_COMPLEX);
 908      resolve_equivalent (&M_COMPL);
 909      resolve_equivalent (&M_LONG_COMPLEX);
 910      resolve_equivalent (&M_LONG_COMPL);
 911      resolve_equivalent (&M_LONG_LONG_COMPLEX);
 912      resolve_equivalent (&M_LONG_LONG_COMPL);
 913      resolve_equivalent (&M_SEMA);
 914      resolve_equivalent (&M_PIPE);
 915  // UNION members could be resolved.
 916      absorb_unions (TOP_MOID (mod));
 917      contract_unions (TOP_MOID (mod));
 918  // FLEX INDICANT could be resolved.
 919      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 920        if (IS_FLEX (z) && SUB (z) != NO_MOID) {
 921          if (SUB_SUB (z) != NO_MOID && IS (SUB_SUB (z), STRUCT_SYMBOL)) {
 922            MULTIPLE (z) = make_flex_multiple_struct (SUB_SUB (z), &TOP_MOID (mod), DIM (SUB (z)));
 923          }
 924        }
 925      }
 926  // See what new known modes we have generated by resolving..
 927      for (z = TOP_MOID (mod); z != STANDENV_MOID (&A68_JOB); FORWARD (z)) {
 928        MOID_T *v;
 929        for (v = NEXT (z); v != NO_MOID; FORWARD (v)) {
 930          if (prove_moid_equivalence (z, v)) {
 931            EQUIVALENT (z) = v;
 932            EQUIVALENT (v) = NO_MOID;
 933          }
 934        }
 935      }
 936  // Count the modes to check self consistency.
 937      len = nlen;
 938      for (nlen = 0, z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 939        nlen++;
 940      }
 941    }
 942    ABEND (M_STRING != M_FLEX_ROW_CHAR, ERROR_INTERNAL_CONSISTENCY, __func__);
 943  // Find out what modes contain rows.
 944    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 945      HAS_ROWS (z) = is_mode_has_row (z);
 946    }
 947  // Check flexible modes.
 948    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 949      if (IS_FLEX (z) && !IS (SUB (z), ROW_SYMBOL)) {
 950        diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
 951      }
 952    }
 953  // Check on fields in structured modes f.i. STRUCT (REAL x, INT n, REAL x) is wrong.
 954    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 955      if (IS (z, STRUCT_SYMBOL) && EQUIVALENT (z) == NO_MOID) {
 956        PACK_T *s = PACK (z);
 957        for (; s != NO_PACK; FORWARD (s)) {
 958          BOOL_T x = A68_TRUE;
 959          for (PACK_T *t = NEXT (s); t != NO_PACK && x; FORWARD (t)) {
 960            if (TEXT (s) == TEXT (t)) {
 961              diagnostic (A68_ERROR, NODE (z), ERROR_MULTIPLE_FIELD);
 962              while (NEXT (s) != NO_PACK && TEXT (NEXT (s)) == TEXT (t)) {
 963                FORWARD (s);
 964              }
 965              x = A68_FALSE;
 966            }
 967          }
 968        }
 969      }
 970    }
 971  // Various union test.
 972    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 973      if (IS (z, UNION_SYMBOL) && EQUIVALENT (z) == NO_MOID) {
 974        PACK_T *s = PACK (z);
 975  // Discard unions with one member.
 976        if (count_pack_members (s) == 1) {
 977          diagnostic (A68_ERROR, NODE (z), ERROR_COMPONENT_NUMBER, z);
 978        }
 979  // Discard incestuous unions with firmly related modes.
 980        for (; s != NO_PACK; FORWARD (s)) {
 981          PACK_T *t;
 982          for (t = NEXT (s); t != NO_PACK; FORWARD (t)) {
 983            if (MOID (t) != MOID (s)) {
 984              if (is_firm (MOID (s), MOID (t))) {
 985                diagnostic (A68_ERROR, NODE (z), ERROR_COMPONENT_RELATED, z);
 986              }
 987            }
 988          }
 989        }
 990  // Discard incestuous unions with firmly related subsets.
 991        for (s = PACK (z); s != NO_PACK; FORWARD (s)) {
 992          MOID_T *n = depref_completely (MOID (s));
 993          if (IS (n, UNION_SYMBOL) && is_subset (n, z, NO_DEFLEXING)) {
 994            diagnostic (A68_ERROR, NODE (z), ERROR_SUBSET_RELATED, z, n);
 995          }
 996        }
 997      }
 998    }
 999  // Wrap up and exit.
1000    free_postulate_list (A68 (top_postulate), NO_POSTULATE);
1001    A68 (top_postulate) = NO_POSTULATE;
1002  }
1003  
1004  //! @brief Make list of all modes in the program.
1005  
1006  void make_moid_list (MODULE_T * mod)
1007  {
1008    BOOL_T cont = A68_TRUE;
1009  // Collect modes from the syntax tree.
1010    reset_moid_tree (TOP_NODE (mod));
1011    get_modes_from_tree (TOP_NODE (mod), STOP);
1012    get_mode_from_proc_var_declarations_tree (TOP_NODE (mod));
1013  // Connect indicants to their declarers.
1014    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1015      if (IS (z, INDICANT)) {
1016        NODE_T *u = NODE (z);
1017        ABEND (NEXT (u) == NO_NODE, ERROR_INTERNAL_CONSISTENCY, __func__);
1018        ABEND (NEXT_NEXT (u) == NO_NODE, ERROR_INTERNAL_CONSISTENCY, __func__);
1019        ABEND (MOID (NEXT_NEXT (u)) == NO_MOID, ERROR_INTERNAL_CONSISTENCY, __func__);
1020        EQUIVALENT (z) = MOID (NEXT_NEXT (u));
1021      }
1022    }
1023  // Checks on wrong declarations.
1024    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1025      USE (z) = A68_FALSE;
1026    }
1027    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1028      if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) {
1029        if (!is_well_formed (z, EQUIVALENT (z), A68_FALSE, A68_FALSE, A68_TRUE)) {
1030          diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
1031          cont = A68_FALSE;
1032        }
1033      }
1034    }
1035    for (MOID_T *z = TOP_MOID (mod); cont && z != NO_MOID; FORWARD (z)) {
1036      if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) {
1037        ;
1038      } else if (NODE (z) != NO_NODE) {
1039        if (!is_well_formed (NO_MOID, z, A68_FALSE, A68_FALSE, A68_TRUE)) {
1040          diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
1041        }
1042      }
1043    }
1044    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1045      ABEND (USE (z), ERROR_INTERNAL_CONSISTENCY, __func__);
1046    }
1047    if (ERROR_COUNT (mod) != 0) {
1048      return;
1049    }
1050    compute_derived_modes (mod);
1051    init_postulates ();
1052  }