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 (A68_LEVEL <= 2)
 526        if (sizety == 0) {
 527          MOID (p) = M_BITS;
 528        } else if (sizety == 1) {
 529          MOID (p) = M_LONG_BITS;
 530        } else if (sizety == 2) {
 531          MOID (p) = M_LONG_LONG_BITS;
 532        } else {
 533          MOID (p) = (sizety > 0 ? M_LONG_LONG_BITS : M_BITS);
 534        }
 535  #else
 536        if (sizety == 0) {
 537          MOID (p) = M_BITS;
 538        } else if (sizety == 1) {
 539          MOID (p) = M_LONG_BITS;
 540        } else {
 541          MOID (p) = (sizety > 0 ? M_LONG_BITS : M_BITS);
 542        }
 543  #endif
 544      } else if (IS (p, LONGETY) || IS (p, SHORTETY)) {
 545        get_mode_from_denotation (NEXT (p), count_sizety (SUB (p)));
 546        MOID (p) = MOID (NEXT (p));
 547      } else if (IS (p, EMPTY_SYMBOL)) {
 548        MOID (p) = M_VOID;
 549      }
 550    }
 551  }
 552  
 553  //! @brief Collect modes from the syntax tree.
 554  
 555  void get_modes_from_tree (NODE_T * p, int attribute)
 556  {
 557    for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) {
 558      if (IS (q, VOID_SYMBOL)) {
 559        MOID (q) = M_VOID;
 560      } else if (IS (q, DECLARER)) {
 561        if (attribute == VARIABLE_DECLARATION) {
 562          MOID_T *new_one = get_mode_from_declarer (q);
 563          MOID (q) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK);
 564        } else {
 565          MOID (q) = get_mode_from_declarer (q);
 566        }
 567      } else if (IS (q, ROUTINE_TEXT)) {
 568        MOID (q) = get_mode_from_routine_text (SUB (q));
 569      } else if (IS (q, OPERATOR_PLAN)) {
 570        MOID (q) = get_mode_from_operator (SUB (q));
 571      } else if (is_one_of (q, LOC_SYMBOL, HEAP_SYMBOL, NEW_SYMBOL, STOP)) {
 572        if (attribute == GENERATOR) {
 573          MOID_T *new_one = get_mode_from_declarer (NEXT (q));
 574          MOID (NEXT (q)) = new_one;
 575          MOID (q) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK);
 576        }
 577      } else {
 578        if (attribute == DENOTATION) {
 579          get_mode_from_denotation (q, 0);
 580        }
 581      }
 582    }
 583    if (attribute != DENOTATION) {
 584      for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) {
 585        if (SUB (q) != NO_NODE) {
 586          get_modes_from_tree (SUB (q), ATTRIBUTE (q));
 587        }
 588      }
 589    }
 590  }
 591  
 592  //! @brief Collect modes from proc variables.
 593  
 594  void get_mode_from_proc_variables (NODE_T * p)
 595  {
 596    if (p != NO_NODE) {
 597      if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
 598        get_mode_from_proc_variables (SUB (p));
 599        get_mode_from_proc_variables (NEXT (p));
 600      } else if (IS (p, QUALIFIER) || IS (p, PROC_SYMBOL) || IS (p, COMMA_SYMBOL)) {
 601        get_mode_from_proc_variables (NEXT (p));
 602      } else if (IS (p, DEFINING_IDENTIFIER)) {
 603        MOID_T *new_one = MOID (NEXT_NEXT (p));
 604        MOID (p) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, p, new_one, NO_PACK);
 605      }
 606    }
 607  }
 608  
 609  //! @brief Collect modes from proc variable declarations.
 610  
 611  void get_mode_from_proc_var_declarations_tree (NODE_T * p)
 612  {
 613    for (; p != NO_NODE; FORWARD (p)) {
 614      get_mode_from_proc_var_declarations_tree (SUB (p));
 615      if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
 616        get_mode_from_proc_variables (p);
 617      }
 618    }
 619  }
 620  
 621  // Various routines to test modes.
 622  
 623  //! @brief Whether a mode declaration refers to self or relates to void.
 624  
 625  BOOL_T is_well_formed (MOID_T * def, MOID_T * z, BOOL_T yin, BOOL_T yang, BOOL_T video)
 626  {
 627    if (z == NO_MOID) {
 628      return A68_FALSE;
 629    } else if (yin && yang) {
 630      return z == M_VOID ? video : A68_TRUE;
 631    } else if (z == M_VOID) {
 632      return video;
 633    } else if (IS (z, STANDARD)) {
 634      return A68_TRUE;
 635    } else if (IS (z, INDICANT)) {
 636      if (def == NO_MOID) {
 637  // Check an applied indicant for relation to VOID.
 638        while (z != NO_MOID) {
 639          z = EQUIVALENT (z);
 640        }
 641        if (z == M_VOID) {
 642          return video;
 643        } else {
 644          return A68_TRUE;
 645        }
 646      } else {
 647        if (z == def || USE (z)) {
 648          return yin && yang;
 649        } else {
 650          USE (z) = A68_TRUE;
 651          BOOL_T wwf = is_well_formed (def, EQUIVALENT (z), yin, yang, video);
 652          USE (z) = A68_FALSE;
 653          return wwf;
 654        }
 655      }
 656    } else if (IS_REF (z)) {
 657      return is_well_formed (def, SUB (z), A68_TRUE, yang, A68_FALSE);
 658    } else if (IS (z, PROC_SYMBOL)) {
 659      return PACK (z) != NO_PACK ? A68_TRUE : is_well_formed (def, SUB (z), A68_TRUE, yang, A68_TRUE);
 660    } else if (IS_ROW (z)) {
 661      return is_well_formed (def, SUB (z), yin, yang, A68_FALSE);
 662    } else if (IS_FLEX (z)) {
 663      return is_well_formed (def, SUB (z), yin, yang, A68_FALSE);
 664    } else if (IS (z, STRUCT_SYMBOL)) {
 665      for (PACK_T *s = PACK (z); s != NO_PACK; FORWARD (s)) {
 666        if (!is_well_formed (def, MOID (s), yin, A68_TRUE, A68_FALSE)) {
 667          return A68_FALSE;
 668        }
 669      }
 670      return A68_TRUE;
 671    } else if (IS (z, UNION_SYMBOL)) {
 672      for (PACK_T *s = PACK (z); s != NO_PACK; FORWARD (s)) {
 673        if (!is_well_formed (def, MOID (s), yin, yang, A68_TRUE)) {
 674          return A68_FALSE;
 675        }
 676      }
 677      return A68_TRUE;
 678    } else {
 679      return A68_FALSE;
 680    }
 681  }
 682  
 683  //! @brief Replace a mode by its equivalent mode (walk chain).
 684  
 685  void resolve_eq_members (MOID_T * q)
 686  {
 687    resolve_equivalent (&SUB (q));
 688    resolve_equivalent (&DEFLEXED (q));
 689    resolve_equivalent (&MULTIPLE (q));
 690    resolve_equivalent (&NAME (q));
 691    resolve_equivalent (&SLICE (q));
 692    resolve_equivalent (&TRIM (q));
 693    resolve_equivalent (&ROWED (q));
 694    for (PACK_T *p = PACK (q); p != NO_PACK; FORWARD (p)) {
 695      resolve_equivalent (&MOID (p));
 696    }
 697  }
 698  
 699  //! @brief Track equivalent tags.
 700  
 701  void resolve_eq_tags (TAG_T * z)
 702  {
 703    for (; z != NO_TAG; FORWARD (z)) {
 704      if (MOID (z) != NO_MOID) {
 705        resolve_equivalent (&MOID (z));
 706      }
 707    }
 708  }
 709  
 710  //! @brief Bind modes in syntax tree.
 711  
 712  void bind_modes (NODE_T * p)
 713  {
 714    for (; p != NO_NODE; FORWARD (p)) {
 715      resolve_equivalent (&MOID (p));
 716      if (SUB (p) != NO_NODE && is_new_lexical_level (p)) {
 717        TABLE_T *s = TABLE (SUB (p));
 718        for (TAG_T *z = INDICANTS (s); z != NO_TAG; FORWARD (z)) {
 719          if (NODE (z) != NO_NODE) {
 720            resolve_equivalent (&MOID (NEXT_NEXT (NODE (z))));
 721            MOID (z) = MOID (NEXT_NEXT (NODE (z)));
 722            MOID (NODE (z)) = MOID (z);
 723          }
 724        }
 725      }
 726      bind_modes (SUB (p));
 727    }
 728  }
 729  
 730  // Routines for calculating subordinates for selections, for instance selection
 731  // from REF STRUCT (A) yields REF A fields and selection from [] STRUCT (A) yields
 732  // [] A fields.
 733  
 734  //! @brief Make name pack.
 735  
 736  void make_name_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p)
 737  {
 738    if (src != NO_PACK) {
 739      make_name_pack (NEXT (src), dst, p);
 740      MOID_T *z = add_mode (p, REF_SYMBOL, 0, NO_NODE, MOID (src), NO_PACK);
 741      (void) add_mode_to_pack (dst, z, TEXT (src), NODE (src));
 742    }
 743  }
 744  
 745  //! @brief Make flex multiple row pack.
 746  
 747  void make_flex_multiple_row_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p, int dim)
 748  {
 749    if (src != NO_PACK) {
 750      make_flex_multiple_row_pack (NEXT (src), dst, p, dim);
 751      MOID_T *z = add_row (p, dim, MOID (src), NO_NODE, A68_FALSE);
 752      z = add_mode (p, FLEX_SYMBOL, 0, NO_NODE, z, NO_PACK);
 753      (void) add_mode_to_pack (dst, z, TEXT (src), NODE (src));
 754    }
 755  }
 756  
 757  //! @brief Make name struct.
 758  
 759  MOID_T *make_name_struct (MOID_T * m, MOID_T ** p)
 760  {
 761    PACK_T *u = NO_PACK;
 762    make_name_pack (PACK (m), &u, p);
 763    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 764  }
 765  
 766  //! @brief Make name row.
 767  
 768  MOID_T *make_name_row (MOID_T * m, MOID_T ** p)
 769  {
 770    if (SLICE (m) != NO_MOID) {
 771      return add_mode (p, REF_SYMBOL, 0, NO_NODE, SLICE (m), NO_PACK);
 772    } else if (SUB (m) != NO_MOID) {
 773      return add_mode (p, REF_SYMBOL, 0, NO_NODE, SUB (m), NO_PACK);
 774    } else {
 775      return NO_MOID;             // weird, FLEX INT or so ...
 776    }
 777  }
 778  
 779  //! @brief Make multiple row pack.
 780  
 781  void make_multiple_row_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p, int dim)
 782  {
 783    if (src != NO_PACK) {
 784      make_multiple_row_pack (NEXT (src), dst, p, dim);
 785      (void) add_mode_to_pack (dst, add_row (p, dim, MOID (src), NO_NODE, A68_FALSE), TEXT (src), NODE (src));
 786    }
 787  }
 788  
 789  //! @brief Make flex multiple struct.
 790  
 791  MOID_T *make_flex_multiple_struct (MOID_T * m, MOID_T ** p, int dim)
 792  {
 793    PACK_T *u = NO_PACK;
 794    make_flex_multiple_row_pack (PACK (m), &u, p, dim);
 795    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 796  }
 797  
 798  //! @brief Make multiple struct.
 799  
 800  MOID_T *make_multiple_struct (MOID_T * m, MOID_T ** p, int dim)
 801  {
 802    PACK_T *u = NO_PACK;
 803    make_multiple_row_pack (PACK (m), &u, p, dim);
 804    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 805  }
 806  
 807  //! @brief Whether mode has row.
 808  
 809  BOOL_T is_mode_has_row (MOID_T * m)
 810  {
 811    if (IS (m, STRUCT_SYMBOL) || IS (m, UNION_SYMBOL)) {
 812      BOOL_T k = A68_FALSE;
 813      for (PACK_T *p = PACK (m); p != NO_PACK && k == A68_FALSE; FORWARD (p)) {
 814        HAS_ROWS (MOID (p)) = is_mode_has_row (MOID (p));
 815        k |= (HAS_ROWS (MOID (p)));
 816      }
 817      return k;
 818    } else {
 819      return (BOOL_T) (HAS_ROWS (m) || IS_ROW (m) || IS_FLEX (m));
 820    }
 821  }
 822  
 823  //! @brief Compute derived modes.
 824  
 825  void compute_derived_modes (MODULE_T * mod)
 826  {
 827    MOID_T *z;
 828    int len = 0, nlen = 1;
 829  // UNION things.
 830    absorb_unions (TOP_MOID (mod));
 831    contract_unions (TOP_MOID (mod));
 832  // The for-statement below prevents an endless loop.
 833    for (int k = 1; k <= 10 && len != nlen; k++) {
 834  // Make deflexed modes.
 835      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 836        if (SUB (z) != NO_MOID) {
 837          if (IS_REF_FLEX (z) && DEFLEXED (SUB_SUB (z)) != NO_MOID) {
 838            DEFLEXED (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB_SUB (z)), NO_PACK);
 839          } else if (IS_REF (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 840            DEFLEXED (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB (z)), NO_PACK);
 841          } else if (IS_ROW (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 842            DEFLEXED (z) = add_mode (&TOP_MOID (mod), ROW_SYMBOL, DIM (z), NODE (z), DEFLEXED (SUB (z)), NO_PACK);
 843          } else if (IS_FLEX (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 844            DEFLEXED (z) = DEFLEXED (SUB (z));
 845          } else if (IS_FLEX (z)) {
 846            DEFLEXED (z) = SUB (z);
 847          } else {
 848            DEFLEXED (z) = z;
 849          }
 850        }
 851      }
 852  // Derived modes for stowed modes.
 853      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 854        if (NAME (z) == NO_MOID && IS_REF (z)) {
 855          if (IS (SUB (z), STRUCT_SYMBOL)) {
 856            NAME (z) = make_name_struct (SUB (z), &TOP_MOID (mod));
 857          } else if (IS_ROW (SUB (z))) {
 858            NAME (z) = make_name_row (SUB (z), &TOP_MOID (mod));
 859          } else if (IS_FLEX (SUB (z)) && SUB_SUB (z) != NO_MOID) {
 860            NAME (z) = make_name_row (SUB_SUB (z), &TOP_MOID (mod));
 861          }
 862        }
 863        if (MULTIPLE (z) != NO_MOID) {
 864          ;
 865        } else if (IS_REF (z)) {
 866          if (MULTIPLE (SUB (z)) != NO_MOID) {
 867            MULTIPLE (z) = make_name_struct (MULTIPLE (SUB (z)), &TOP_MOID (mod));
 868          }
 869        } else if (IS_ROW (z)) {
 870          if (IS (SUB (z), STRUCT_SYMBOL)) {
 871            MULTIPLE (z) = make_multiple_struct (SUB (z), &TOP_MOID (mod), DIM (z));
 872          }
 873        }
 874      }
 875      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 876        if (TRIM (z) == NO_MOID && IS_FLEX (z)) {
 877          TRIM (z) = SUB (z);
 878        }
 879        if (TRIM (z) == NO_MOID && IS_REF_FLEX (z)) {
 880          TRIM (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), SUB_SUB (z), NO_PACK);
 881        }
 882      }
 883  // Fill out stuff for rows, f.i. inverse relations.
 884      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 885        if (IS_ROW (z) && DIM (z) > 0 && SUB (z) != NO_MOID && !DERIVATE (z)) {
 886          (void) add_row (&TOP_MOID (mod), DIM (z) + 1, SUB (z), NODE (z), A68_TRUE);
 887        } else if (IS_REF (z) && IS (SUB (z), ROW_SYMBOL) && !DERIVATE (SUB (z))) {
 888          MOID_T *x = add_row (&TOP_MOID (mod), DIM (SUB (z)) + 1, SUB_SUB (z), NODE (SUB (z)), A68_TRUE);
 889          MOID_T *y = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), x, NO_PACK);
 890          NAME (y) = z;
 891        }
 892      }
 893      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 894        if (IS_ROW (z) && SLICE (z) != NO_MOID) {
 895          ROWED (SLICE (z)) = z;
 896        }
 897        if (IS_REF (z)) {
 898          MOID_T *y = SUB (z);
 899          if (SLICE (y) != NO_MOID && IS_ROW (SLICE (y)) && NAME (z) != NO_MOID) {
 900            ROWED (NAME (z)) = z;
 901          }
 902        }
 903      }
 904      bind_modes (TOP_NODE (mod));
 905      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 906        if (IS (z, INDICANT) && NODE (z) != NO_NODE) {
 907          EQUIVALENT (z) = MOID (NODE (z));
 908        }
 909      }
 910      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 911        resolve_eq_members (z);
 912      }
 913      resolve_eq_tags (INDICANTS (A68_STANDENV));
 914      resolve_eq_tags (IDENTIFIERS (A68_STANDENV));
 915      resolve_eq_tags (OPERATORS (A68_STANDENV));
 916      resolve_equivalent (&M_STRING);
 917      resolve_equivalent (&M_COMPLEX);
 918      resolve_equivalent (&M_COMPL);
 919      resolve_equivalent (&M_LONG_COMPLEX);
 920      resolve_equivalent (&M_LONG_COMPL);
 921      resolve_equivalent (&M_LONG_LONG_COMPLEX);
 922      resolve_equivalent (&M_LONG_LONG_COMPL);
 923      resolve_equivalent (&M_SEMA);
 924      resolve_equivalent (&M_PIPE);
 925  // UNION members could be resolved.
 926      absorb_unions (TOP_MOID (mod));
 927      contract_unions (TOP_MOID (mod));
 928  // FLEX INDICANT could be resolved.
 929      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 930        if (IS_FLEX (z) && SUB (z) != NO_MOID) {
 931          if (SUB_SUB (z) != NO_MOID && IS (SUB_SUB (z), STRUCT_SYMBOL)) {
 932            MULTIPLE (z) = make_flex_multiple_struct (SUB_SUB (z), &TOP_MOID (mod), DIM (SUB (z)));
 933          }
 934        }
 935      }
 936  // See what new known modes we have generated by resolving..
 937      for (z = TOP_MOID (mod); z != STANDENV_MOID (&A68_JOB); FORWARD (z)) {
 938        MOID_T *v;
 939        for (v = NEXT (z); v != NO_MOID; FORWARD (v)) {
 940          if (prove_moid_equivalence (z, v)) {
 941            EQUIVALENT (z) = v;
 942            EQUIVALENT (v) = NO_MOID;
 943          }
 944        }
 945      }
 946  // Count the modes to check self consistency.
 947      len = nlen;
 948      for (nlen = 0, z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 949        nlen++;
 950      }
 951    }
 952    ABEND (M_STRING != M_FLEX_ROW_CHAR, ERROR_INTERNAL_CONSISTENCY, __func__);
 953  // Find out what modes contain rows.
 954    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 955      HAS_ROWS (z) = is_mode_has_row (z);
 956    }
 957  // Check flexible modes.
 958    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 959      if (IS_FLEX (z) && !IS (SUB (z), ROW_SYMBOL)) {
 960        diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
 961      }
 962    }
 963  // Check on fields in structured modes f.i. STRUCT (REAL x, INT n, REAL x) is wrong.
 964    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 965      if (IS (z, STRUCT_SYMBOL) && EQUIVALENT (z) == NO_MOID) {
 966        PACK_T *s = PACK (z);
 967        for (; s != NO_PACK; FORWARD (s)) {
 968          BOOL_T x = A68_TRUE;
 969          for (PACK_T *t = NEXT (s); t != NO_PACK && x; FORWARD (t)) {
 970            if (TEXT (s) == TEXT (t)) {
 971              diagnostic (A68_ERROR, NODE (z), ERROR_MULTIPLE_FIELD);
 972              while (NEXT (s) != NO_PACK && TEXT (NEXT (s)) == TEXT (t)) {
 973                FORWARD (s);
 974              }
 975              x = A68_FALSE;
 976            }
 977          }
 978        }
 979      }
 980    }
 981  // Various union test.
 982    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 983      if (IS (z, UNION_SYMBOL) && EQUIVALENT (z) == NO_MOID) {
 984        PACK_T *s = PACK (z);
 985  // Discard unions with one member.
 986        if (count_pack_members (s) == 1) {
 987          diagnostic (A68_ERROR, NODE (z), ERROR_COMPONENT_NUMBER, z);
 988        }
 989  // Discard incestuous unions with firmly related modes.
 990        for (; s != NO_PACK; FORWARD (s)) {
 991          PACK_T *t;
 992          for (t = NEXT (s); t != NO_PACK; FORWARD (t)) {
 993            if (MOID (t) != MOID (s)) {
 994              if (is_firm (MOID (s), MOID (t))) {
 995                diagnostic (A68_ERROR, NODE (z), ERROR_COMPONENT_RELATED, z);
 996              }
 997            }
 998          }
 999        }
1000  // Discard incestuous unions with firmly related subsets.
1001        for (s = PACK (z); s != NO_PACK; FORWARD (s)) {
1002          MOID_T *n = depref_completely (MOID (s));
1003          if (IS (n, UNION_SYMBOL) && is_subset (n, z, NO_DEFLEXING)) {
1004            diagnostic (A68_ERROR, NODE (z), ERROR_SUBSET_RELATED, z, n);
1005          }
1006        }
1007      }
1008    }
1009  // Wrap up and exit.
1010    free_postulate_list (A68 (top_postulate), NO_POSTULATE);
1011    A68 (top_postulate) = NO_POSTULATE;
1012  }
1013  
1014  //! @brief Make list of all modes in the program.
1015  
1016  void make_moid_list (MODULE_T * mod)
1017  {
1018    BOOL_T cont = A68_TRUE;
1019  // Collect modes from the syntax tree.
1020    reset_moid_tree (TOP_NODE (mod));
1021    get_modes_from_tree (TOP_NODE (mod), STOP);
1022    get_mode_from_proc_var_declarations_tree (TOP_NODE (mod));
1023  // Connect indicants to their declarers.
1024    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1025      if (IS (z, INDICANT)) {
1026        NODE_T *u = NODE (z);
1027        ABEND (NEXT (u) == NO_NODE, ERROR_INTERNAL_CONSISTENCY, __func__);
1028        ABEND (NEXT_NEXT (u) == NO_NODE, ERROR_INTERNAL_CONSISTENCY, __func__);
1029        ABEND (MOID (NEXT_NEXT (u)) == NO_MOID, ERROR_INTERNAL_CONSISTENCY, __func__);
1030        EQUIVALENT (z) = MOID (NEXT_NEXT (u));
1031      }
1032    }
1033  // Checks on wrong declarations.
1034    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1035      USE (z) = A68_FALSE;
1036    }
1037    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1038      if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) {
1039        if (!is_well_formed (z, EQUIVALENT (z), A68_FALSE, A68_FALSE, A68_TRUE)) {
1040          diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
1041          cont = A68_FALSE;
1042        }
1043      }
1044    }
1045    for (MOID_T *z = TOP_MOID (mod); cont && z != NO_MOID; FORWARD (z)) {
1046      if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) {
1047        ;
1048      } else if (NODE (z) != NO_NODE) {
1049        if (!is_well_formed (NO_MOID, z, A68_FALSE, A68_FALSE, A68_TRUE)) {
1050          diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
1051        }
1052      }
1053    }
1054    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1055      ABEND (USE (z), ERROR_INTERNAL_CONSISTENCY, __func__);
1056    }
1057    if (ERROR_COUNT (mod) != 0) {
1058      return;
1059    }
1060    compute_derived_modes (mod);
1061    init_postulates ();
1062  }