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-2025 J. Marcel van der Veer [algol68g@xs4all.nl].
   8  
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it 
  12  //! under the terms of the GNU General Public License as published by the 
  13  //! Free Software Foundation; either version 3 of the License, or 
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but 
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  //! more details. You should have received a copy of the GNU General Public 
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis
  23  //!
  24  //! 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  // Check whether a standard mode with length 'sizety' exists.
 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  // If no standard mode exists, map onto nearest length.
 282    if (sizety < 0) {
 283      return search_standard_mode (sizety + 1, indicant);
 284    } else if (sizety > 0) {
 285      return search_standard_mode (sizety - 1, indicant);
 286    } else {
 287      return NO_MOID;
 288    }
 289  }
 290  
 291  //! @brief Collect mode from STRUCT field.
 292  
 293  void get_mode_from_struct_field (NODE_T * p, PACK_T ** u)
 294  {
 295    if (p != NO_NODE) {
 296      if (IS (p, IDENTIFIER)) {
 297        ATTRIBUTE (p) = FIELD_IDENTIFIER;
 298        (void) add_mode_to_pack (u, NO_MOID, NSYMBOL (p), p);
 299      } else if (IS (p, DECLARER)) {
 300        MOID_T *new_one = get_mode_from_declarer (p);
 301        get_mode_from_struct_field (NEXT (p), u);
 302        for (PACK_T *t = *u; t && MOID (t) == NO_MOID; FORWARD (t)) {
 303          MOID (t) = new_one;
 304          MOID (NODE (t)) = new_one;
 305        }
 306      } else {
 307        get_mode_from_struct_field (NEXT (p), u);
 308        get_mode_from_struct_field (SUB (p), u);
 309      }
 310    }
 311  }
 312  
 313  //! @brief Collect MODE from formal pack.
 314  
 315  void get_mode_from_formal_pack (NODE_T * p, PACK_T ** u)
 316  {
 317    if (p != NO_NODE) {
 318      if (IS (p, DECLARER)) {
 319        get_mode_from_formal_pack (NEXT (p), u);
 320        MOID_T *z = get_mode_from_declarer (p);
 321        (void) add_mode_to_pack (u, z, NO_TEXT, p);
 322      } else {
 323        get_mode_from_formal_pack (NEXT (p), u);
 324        get_mode_from_formal_pack (SUB (p), u);
 325      }
 326    }
 327  }
 328  
 329  //! @brief Collect MODE or VOID from formal UNION pack.
 330  
 331  void get_mode_from_union_pack (NODE_T * p, PACK_T ** u)
 332  {
 333    if (p != NO_NODE) {
 334      if (IS (p, DECLARER) || IS (p, VOID_SYMBOL)) {
 335        get_mode_from_union_pack (NEXT (p), u);
 336        MOID_T *z = get_mode_from_declarer (p);
 337        (void) add_mode_to_pack (u, z, NO_TEXT, p);
 338      } else {
 339        get_mode_from_union_pack (NEXT (p), u);
 340        get_mode_from_union_pack (SUB (p), u);
 341      }
 342    }
 343  }
 344  
 345  //! @brief Collect mode from PROC, OP pack.
 346  
 347  void get_mode_from_routine_pack (NODE_T * p, PACK_T ** u)
 348  {
 349    if (p != NO_NODE) {
 350      if (IS (p, IDENTIFIER)) {
 351        (void) add_mode_to_pack (u, NO_MOID, NO_TEXT, p);
 352      } else if (IS (p, DECLARER)) {
 353        MOID_T *z = get_mode_from_declarer (p);
 354        for (PACK_T *t = *u; t != NO_PACK && MOID (t) == NO_MOID; FORWARD (t)) {
 355          MOID (t) = z;
 356          MOID (NODE (t)) = z;
 357        }
 358        (void) add_mode_to_pack (u, z, NO_TEXT, p);
 359      } else {
 360        get_mode_from_routine_pack (NEXT (p), u);
 361        get_mode_from_routine_pack (SUB (p), u);
 362      }
 363    }
 364  }
 365  
 366  //! @brief Collect MODE from DECLARER.
 367  
 368  MOID_T *get_mode_from_declarer (NODE_T * p)
 369  {
 370    if (p == NO_NODE) {
 371      return NO_MOID;
 372    } else {
 373      if (IS (p, DECLARER)) {
 374        if (MOID (p) != NO_MOID) {
 375          return MOID (p);
 376        } else {
 377          return MOID (p) = get_mode_from_declarer (SUB (p));
 378        }
 379      } else {
 380        if (IS (p, VOID_SYMBOL)) {
 381          MOID (p) = M_VOID;
 382          return MOID (p);
 383        } else if (IS (p, LONGETY)) {
 384          if (whether (p, LONGETY, INDICANT, STOP)) {
 385            int k = count_sizety (SUB (p));
 386            MOID (p) = search_standard_mode (k, NEXT (p));
 387            return MOID (p);
 388          } else {
 389            return NO_MOID;
 390          }
 391        } else if (IS (p, SHORTETY)) {
 392          if (whether (p, SHORTETY, INDICANT, STOP)) {
 393            int k = count_sizety (SUB (p));
 394            MOID (p) = search_standard_mode (k, NEXT (p));
 395            return MOID (p);
 396          } else {
 397            return NO_MOID;
 398          }
 399        } else if (IS (p, INDICANT)) {
 400          MOID_T *q = search_standard_mode (0, p);
 401          if (q != NO_MOID) {
 402            MOID (p) = q;
 403          } else {
 404  // Position of definition tells indicants apart.
 405            TAG_T *y = find_tag_global (TABLE (p), INDICANT, NSYMBOL (p));
 406            if (y == NO_TAG) {
 407              diagnostic (A68_ERROR, p, ERROR_UNDECLARED_TAG_2, NSYMBOL (p));
 408            } else {
 409              MOID (p) = add_mode (&TOP_MOID (&A68_JOB), INDICANT, 0, NODE (y), NO_MOID, NO_PACK);
 410            }
 411          }
 412          return MOID (p);
 413        } else if (IS_REF (p)) {
 414          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 415          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, p, new_one, NO_PACK);
 416          return MOID (p);
 417        } else if (IS_FLEX (p)) {
 418          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 419          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), FLEX_SYMBOL, 0, p, new_one, NO_PACK);
 420          SLICE (MOID (p)) = SLICE (new_one);
 421          return MOID (p);
 422        } else if (IS (p, FORMAL_BOUNDS)) {
 423          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 424          MOID (p) = add_row (&TOP_MOID (&A68_JOB), 1 + count_formal_bounds (SUB (p)), new_one, p, A68_FALSE);
 425          return MOID (p);
 426        } else if (IS (p, BOUNDS)) {
 427          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 428          MOID (p) = add_row (&TOP_MOID (&A68_JOB), count_bounds (SUB (p)), new_one, p, A68_FALSE);
 429          return MOID (p);
 430        } else if (IS (p, STRUCT_SYMBOL)) {
 431          PACK_T *u = NO_PACK;
 432          get_mode_from_struct_field (NEXT (p), &u);
 433          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), STRUCT_SYMBOL, count_pack_members (u), p, NO_MOID, u);
 434          return MOID (p);
 435        } else if (IS (p, UNION_SYMBOL)) {
 436          PACK_T *u = NO_PACK;
 437          get_mode_from_union_pack (NEXT (p), &u);
 438          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), UNION_SYMBOL, count_pack_members (u), p, NO_MOID, u);
 439          return MOID (p);
 440        } else if (IS (p, PROC_SYMBOL)) {
 441          NODE_T *save = p;
 442          PACK_T *u = NO_PACK;
 443          if (IS (NEXT (p), FORMAL_DECLARERS)) {
 444            get_mode_from_formal_pack (SUB_NEXT (p), &u);
 445            FORWARD (p);
 446          }
 447          MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 448          MOID (p) = add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, count_pack_members (u), save, new_one, u);
 449          MOID (save) = MOID (p);
 450          return MOID (p);
 451        } else {
 452          return NO_MOID;
 453        }
 454      }
 455    }
 456  }
 457  
 458  //! @brief Collect MODEs from a routine-text header.
 459  
 460  MOID_T *get_mode_from_routine_text (NODE_T * p)
 461  {
 462    PACK_T *u = NO_PACK;
 463    NODE_T *q = p;
 464    if (IS (p, PARAMETER_PACK)) {
 465      get_mode_from_routine_pack (SUB (p), &u);
 466      FORWARD (p);
 467    }
 468    MOID_T *n = get_mode_from_declarer (p);
 469    return add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, count_pack_members (u), q, n, u);
 470  }
 471  
 472  //! @brief Collect modes from operator-plan.
 473  
 474  MOID_T *get_mode_from_operator (NODE_T * p)
 475  {
 476    PACK_T *u = NO_PACK;
 477    NODE_T *save = p;
 478    if (IS (NEXT (p), FORMAL_DECLARERS)) {
 479      get_mode_from_formal_pack (SUB_NEXT (p), &u);
 480      FORWARD (p);
 481    }
 482    MOID_T *new_one = get_mode_from_declarer (NEXT (p));
 483    MOID (p) = add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, count_pack_members (u), save, new_one, u);
 484    return MOID (p);
 485  }
 486  
 487  //! @brief Collect mode from denotation.
 488  
 489  void get_mode_from_denotation (NODE_T * p, int sizety)
 490  {
 491    if (p != NO_NODE) {
 492      if (IS (p, ROW_CHAR_DENOTATION)) {
 493        if (strlen (NSYMBOL (p)) == 1) {
 494          MOID (p) = M_CHAR;
 495        } else {
 496          MOID (p) = M_ROW_CHAR;
 497        }
 498      } else if (IS (p, TRUE_SYMBOL) || IS (p, FALSE_SYMBOL)) {
 499        MOID (p) = M_BOOL;
 500      } else if (IS (p, INT_DENOTATION)) {
 501        if (sizety == 0) {
 502          MOID (p) = M_INT;
 503        } else if (sizety == 1) {
 504          MOID (p) = M_LONG_INT;
 505        } else if (sizety == 2) {
 506          MOID (p) = M_LONG_LONG_INT;
 507        } else {
 508          MOID (p) = (sizety > 0 ? M_LONG_LONG_INT : M_INT);
 509        }
 510      } else if (IS (p, REAL_DENOTATION)) {
 511        if (sizety == 0) {
 512          MOID (p) = M_REAL;
 513        } else if (sizety == 1) {
 514          MOID (p) = M_LONG_REAL;
 515        } else if (sizety == 2) {
 516          MOID (p) = M_LONG_LONG_REAL;
 517        } else {
 518          MOID (p) = (sizety > 0 ? M_LONG_LONG_REAL : M_REAL);
 519        }
 520      } else if (IS (p, BITS_DENOTATION)) {
 521  #if (A68_LEVEL <= 2)
 522        if (sizety == 0) {
 523          MOID (p) = M_BITS;
 524        } else if (sizety == 1) {
 525          MOID (p) = M_LONG_BITS;
 526        } else if (sizety == 2) {
 527          MOID (p) = M_LONG_LONG_BITS;
 528        } else {
 529          MOID (p) = (sizety > 0 ? M_LONG_LONG_BITS : M_BITS);
 530        }
 531  #else
 532        if (sizety == 0) {
 533          MOID (p) = M_BITS;
 534        } else if (sizety == 1) {
 535          MOID (p) = M_LONG_BITS;
 536        } else {
 537          MOID (p) = (sizety > 0 ? M_LONG_BITS : M_BITS);
 538        }
 539  #endif
 540      } else if (IS (p, LONGETY) || IS (p, SHORTETY)) {
 541        get_mode_from_denotation (NEXT (p), count_sizety (SUB (p)));
 542        MOID (p) = MOID (NEXT (p));
 543      } else if (IS (p, EMPTY_SYMBOL)) {
 544        MOID (p) = M_VOID;
 545      }
 546    }
 547  }
 548  
 549  //! @brief Collect modes from the syntax tree.
 550  
 551  void get_modes_from_tree (NODE_T * p, int attribute)
 552  {
 553    for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) {
 554      if (IS (q, VOID_SYMBOL)) {
 555        MOID (q) = M_VOID;
 556      } else if (IS (q, DECLARER)) {
 557        if (attribute == VARIABLE_DECLARATION) {
 558          MOID_T *new_one = get_mode_from_declarer (q);
 559          MOID (q) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK);
 560        } else {
 561          MOID (q) = get_mode_from_declarer (q);
 562        }
 563      } else if (IS (q, ROUTINE_TEXT)) {
 564        MOID (q) = get_mode_from_routine_text (SUB (q));
 565      } else if (IS (q, OPERATOR_PLAN)) {
 566        MOID (q) = get_mode_from_operator (SUB (q));
 567      } else if (is_one_of (q, LOC_SYMBOL, HEAP_SYMBOL, NEW_SYMBOL, STOP)) {
 568        if (attribute == GENERATOR) {
 569          MOID_T *new_one = get_mode_from_declarer (NEXT (q));
 570          MOID (NEXT (q)) = new_one;
 571          MOID (q) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK);
 572        }
 573      } else {
 574        if (attribute == DENOTATION) {
 575          get_mode_from_denotation (q, 0);
 576        }
 577      }
 578    }
 579    if (attribute != DENOTATION) {
 580      for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) {
 581        if (SUB (q) != NO_NODE) {
 582          get_modes_from_tree (SUB (q), ATTRIBUTE (q));
 583        }
 584      }
 585    }
 586  }
 587  
 588  //! @brief Collect modes from proc variables.
 589  
 590  void get_mode_from_proc_variables (NODE_T * p)
 591  {
 592    if (p != NO_NODE) {
 593      if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
 594        get_mode_from_proc_variables (SUB (p));
 595        get_mode_from_proc_variables (NEXT (p));
 596      } else if (IS (p, QUALIFIER) || IS (p, PROC_SYMBOL) || IS (p, COMMA_SYMBOL)) {
 597        get_mode_from_proc_variables (NEXT (p));
 598      } else if (IS (p, DEFINING_IDENTIFIER)) {
 599        MOID_T *new_one = MOID (NEXT_NEXT (p));
 600        MOID (p) = add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, p, new_one, NO_PACK);
 601      }
 602    }
 603  }
 604  
 605  //! @brief Collect modes from proc variable declarations.
 606  
 607  void get_mode_from_proc_var_declarations_tree (NODE_T * p)
 608  {
 609    for (; p != NO_NODE; FORWARD (p)) {
 610      get_mode_from_proc_var_declarations_tree (SUB (p));
 611      if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
 612        get_mode_from_proc_variables (p);
 613      }
 614    }
 615  }
 616  
 617  // Various routines to test modes.
 618  
 619  //! @brief Whether a mode declaration refers to self or relates to void.
 620  
 621  BOOL_T is_well_formed (MOID_T * def, MOID_T * z, BOOL_T yin, BOOL_T yang, BOOL_T video)
 622  {
 623    if (z == NO_MOID) {
 624      return A68_FALSE;
 625    } else if (yin && yang) {
 626      return z == M_VOID ? video : A68_TRUE;
 627    } else if (z == M_VOID) {
 628      return video;
 629    } else if (IS (z, STANDARD)) {
 630      return A68_TRUE;
 631    } else if (IS (z, INDICANT)) {
 632      if (def == NO_MOID) {
 633  // Check an applied indicant for relation to VOID.
 634        while (z != NO_MOID) {
 635          z = EQUIVALENT (z);
 636        }
 637        if (z == M_VOID) {
 638          return video;
 639        } else {
 640          return A68_TRUE;
 641        }
 642      } else {
 643        if (z == def || USE (z)) {
 644          return yin && yang;
 645        } else {
 646          USE (z) = A68_TRUE;
 647          BOOL_T wwf = is_well_formed (def, EQUIVALENT (z), yin, yang, video);
 648          USE (z) = A68_FALSE;
 649          return wwf;
 650        }
 651      }
 652    } else if (IS_REF (z)) {
 653      return is_well_formed (def, SUB (z), A68_TRUE, yang, A68_FALSE);
 654    } else if (IS (z, PROC_SYMBOL)) {
 655      return PACK (z) != NO_PACK ? A68_TRUE : is_well_formed (def, SUB (z), A68_TRUE, yang, A68_TRUE);
 656    } else if (IS_ROW (z)) {
 657      return is_well_formed (def, SUB (z), yin, yang, A68_FALSE);
 658    } else if (IS_FLEX (z)) {
 659      return is_well_formed (def, SUB (z), yin, yang, A68_FALSE);
 660    } else if (IS (z, STRUCT_SYMBOL)) {
 661      for (PACK_T *s = PACK (z); s != NO_PACK; FORWARD (s)) {
 662        if (!is_well_formed (def, MOID (s), yin, A68_TRUE, A68_FALSE)) {
 663          return A68_FALSE;
 664        }
 665      }
 666      return A68_TRUE;
 667    } else if (IS (z, UNION_SYMBOL)) {
 668      for (PACK_T *s = PACK (z); s != NO_PACK; FORWARD (s)) {
 669        if (!is_well_formed (def, MOID (s), yin, yang, A68_TRUE)) {
 670          return A68_FALSE;
 671        }
 672      }
 673      return A68_TRUE;
 674    } else {
 675      return A68_FALSE;
 676    }
 677  }
 678  
 679  //! @brief Replace a mode by its equivalent mode (walk chain).
 680  
 681  void resolve_eq_members (MOID_T * q)
 682  {
 683    resolve_equivalent (&SUB (q));
 684    resolve_equivalent (&DEFLEXED (q));
 685    resolve_equivalent (&MULTIPLE (q));
 686    resolve_equivalent (&NAME (q));
 687    resolve_equivalent (&SLICE (q));
 688    resolve_equivalent (&TRIM (q));
 689    resolve_equivalent (&ROWED (q));
 690    for (PACK_T *p = PACK (q); p != NO_PACK; FORWARD (p)) {
 691      resolve_equivalent (&MOID (p));
 692    }
 693  }
 694  
 695  //! @brief Track equivalent tags.
 696  
 697  void resolve_eq_tags (TAG_T * z)
 698  {
 699    for (; z != NO_TAG; FORWARD (z)) {
 700      if (MOID (z) != NO_MOID) {
 701        resolve_equivalent (&MOID (z));
 702      }
 703    }
 704  }
 705  
 706  //! @brief Bind modes in syntax tree.
 707  
 708  void bind_modes (NODE_T * p)
 709  {
 710    for (; p != NO_NODE; FORWARD (p)) {
 711      resolve_equivalent (&MOID (p));
 712      if (SUB (p) != NO_NODE && is_new_lexical_level (p)) {
 713        TABLE_T *s = TABLE (SUB (p));
 714        for (TAG_T *z = INDICANTS (s); z != NO_TAG; FORWARD (z)) {
 715          if (NODE (z) != NO_NODE) {
 716            resolve_equivalent (&MOID (NEXT_NEXT (NODE (z))));
 717            MOID (z) = MOID (NEXT_NEXT (NODE (z)));
 718            MOID (NODE (z)) = MOID (z);
 719          }
 720        }
 721      }
 722      bind_modes (SUB (p));
 723    }
 724  }
 725  
 726  // Routines for calculating subordinates for selections, for instance selection
 727  // from REF STRUCT (A) yields REF A fields and selection from [] STRUCT (A) yields
 728  // [] A fields.
 729  
 730  //! @brief Make name pack.
 731  
 732  void make_name_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p)
 733  {
 734    if (src != NO_PACK) {
 735      make_name_pack (NEXT (src), dst, p);
 736      MOID_T *z = add_mode (p, REF_SYMBOL, 0, NO_NODE, MOID (src), NO_PACK);
 737      (void) add_mode_to_pack (dst, z, TEXT (src), NODE (src));
 738    }
 739  }
 740  
 741  //! @brief Make flex multiple row pack.
 742  
 743  void make_flex_multiple_row_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p, int dim)
 744  {
 745    if (src != NO_PACK) {
 746      make_flex_multiple_row_pack (NEXT (src), dst, p, dim);
 747      MOID_T *z = add_row (p, dim, MOID (src), NO_NODE, A68_FALSE);
 748      z = add_mode (p, FLEX_SYMBOL, 0, NO_NODE, z, NO_PACK);
 749      (void) add_mode_to_pack (dst, z, TEXT (src), NODE (src));
 750    }
 751  }
 752  
 753  //! @brief Make name struct.
 754  
 755  MOID_T *make_name_struct (MOID_T * m, MOID_T ** p)
 756  {
 757    PACK_T *u = NO_PACK;
 758    make_name_pack (PACK (m), &u, p);
 759    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 760  }
 761  
 762  //! @brief Make name row.
 763  
 764  MOID_T *make_name_row (MOID_T * m, MOID_T ** p)
 765  {
 766    if (SLICE (m) != NO_MOID) {
 767      return add_mode (p, REF_SYMBOL, 0, NO_NODE, SLICE (m), NO_PACK);
 768    } else if (SUB (m) != NO_MOID) {
 769      return add_mode (p, REF_SYMBOL, 0, NO_NODE, SUB (m), NO_PACK);
 770    } else {
 771      return NO_MOID;             // weird, FLEX INT or so ...
 772    }
 773  }
 774  
 775  //! @brief Make multiple row pack.
 776  
 777  void make_multiple_row_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p, int dim)
 778  {
 779    if (src != NO_PACK) {
 780      make_multiple_row_pack (NEXT (src), dst, p, dim);
 781      (void) add_mode_to_pack (dst, add_row (p, dim, MOID (src), NO_NODE, A68_FALSE), TEXT (src), NODE (src));
 782    }
 783  }
 784  
 785  //! @brief Make flex multiple struct.
 786  
 787  MOID_T *make_flex_multiple_struct (MOID_T * m, MOID_T ** p, int dim)
 788  {
 789    PACK_T *u = NO_PACK;
 790    make_flex_multiple_row_pack (PACK (m), &u, p, dim);
 791    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 792  }
 793  
 794  //! @brief Make multiple struct.
 795  
 796  MOID_T *make_multiple_struct (MOID_T * m, MOID_T ** p, int dim)
 797  {
 798    PACK_T *u = NO_PACK;
 799    make_multiple_row_pack (PACK (m), &u, p, dim);
 800    return add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u);
 801  }
 802  
 803  //! @brief Whether mode has row.
 804  
 805  BOOL_T is_mode_has_row (MOID_T * m)
 806  {
 807    if (IS (m, STRUCT_SYMBOL) || IS (m, UNION_SYMBOL)) {
 808      BOOL_T k = A68_FALSE;
 809      for (PACK_T *p = PACK (m); p != NO_PACK && k == A68_FALSE; FORWARD (p)) {
 810        HAS_ROWS (MOID (p)) = is_mode_has_row (MOID (p));
 811        k |= (HAS_ROWS (MOID (p)));
 812      }
 813      return k;
 814    } else {
 815      return (BOOL_T) (HAS_ROWS (m) || IS_ROW (m) || IS_FLEX (m));
 816    }
 817  }
 818  
 819  //! @brief Compute derived modes.
 820  
 821  void compute_derived_modes (MODULE_T * mod)
 822  {
 823    MOID_T *z;
 824    int len = 0, nlen = 1;
 825  // UNION things.
 826    absorb_unions (TOP_MOID (mod));
 827    contract_unions (TOP_MOID (mod));
 828  // The for-statement below prevents an endless loop.
 829    for (int k = 1; k <= 10 && len != nlen; k++) {
 830  // Make deflexed modes.
 831      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 832        if (SUB (z) != NO_MOID) {
 833          if (IS_REF_FLEX (z) && DEFLEXED (SUB_SUB (z)) != NO_MOID) {
 834            DEFLEXED (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB_SUB (z)), NO_PACK);
 835          } else if (IS_REF (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 836            DEFLEXED (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB (z)), NO_PACK);
 837          } else if (IS_ROW (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 838            DEFLEXED (z) = add_mode (&TOP_MOID (mod), ROW_SYMBOL, DIM (z), NODE (z), DEFLEXED (SUB (z)), NO_PACK);
 839          } else if (IS_FLEX (z) && DEFLEXED (SUB (z)) != NO_MOID) {
 840            DEFLEXED (z) = DEFLEXED (SUB (z));
 841          } else if (IS_FLEX (z)) {
 842            DEFLEXED (z) = SUB (z);
 843          } else {
 844            DEFLEXED (z) = z;
 845          }
 846        }
 847      }
 848  // Derived modes for stowed modes.
 849      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 850        if (NAME (z) == NO_MOID && IS_REF (z)) {
 851          if (IS (SUB (z), STRUCT_SYMBOL)) {
 852            NAME (z) = make_name_struct (SUB (z), &TOP_MOID (mod));
 853          } else if (IS_ROW (SUB (z))) {
 854            NAME (z) = make_name_row (SUB (z), &TOP_MOID (mod));
 855          } else if (IS_FLEX (SUB (z)) && SUB_SUB (z) != NO_MOID) {
 856            NAME (z) = make_name_row (SUB_SUB (z), &TOP_MOID (mod));
 857          }
 858        }
 859        if (MULTIPLE (z) != NO_MOID) {
 860          ;
 861        } else if (IS_REF (z)) {
 862          if (MULTIPLE (SUB (z)) != NO_MOID) {
 863            MULTIPLE (z) = make_name_struct (MULTIPLE (SUB (z)), &TOP_MOID (mod));
 864          }
 865        } else if (IS_ROW (z)) {
 866          if (IS (SUB (z), STRUCT_SYMBOL)) {
 867            MULTIPLE (z) = make_multiple_struct (SUB (z), &TOP_MOID (mod), DIM (z));
 868          }
 869        }
 870      }
 871      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 872        if (TRIM (z) == NO_MOID && IS_FLEX (z)) {
 873          TRIM (z) = SUB (z);
 874        }
 875        if (TRIM (z) == NO_MOID && IS_REF_FLEX (z)) {
 876          TRIM (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), SUB_SUB (z), NO_PACK);
 877        }
 878      }
 879  // Fill out stuff for rows, f.i. inverse relations.
 880      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 881        if (IS_ROW (z) && DIM (z) > 0 && SUB (z) != NO_MOID && !DERIVATE (z)) {
 882          (void) add_row (&TOP_MOID (mod), DIM (z) + 1, SUB (z), NODE (z), A68_TRUE);
 883        } else if (IS_REF (z) && IS (SUB (z), ROW_SYMBOL) && !DERIVATE (SUB (z))) {
 884          MOID_T *x = add_row (&TOP_MOID (mod), DIM (SUB (z)) + 1, SUB_SUB (z), NODE (SUB (z)), A68_TRUE);
 885          MOID_T *y = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), x, NO_PACK);
 886          NAME (y) = z;
 887        }
 888      }
 889      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 890        if (IS_ROW (z) && SLICE (z) != NO_MOID) {
 891          ROWED (SLICE (z)) = z;
 892        }
 893        if (IS_REF (z)) {
 894          MOID_T *y = SUB (z);
 895          if (SLICE (y) != NO_MOID && IS_ROW (SLICE (y)) && NAME (z) != NO_MOID) {
 896            ROWED (NAME (z)) = z;
 897          }
 898        }
 899      }
 900      bind_modes (TOP_NODE (mod));
 901      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 902        if (IS (z, INDICANT) && NODE (z) != NO_NODE) {
 903          EQUIVALENT (z) = MOID (NODE (z));
 904        }
 905      }
 906      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 907        resolve_eq_members (z);
 908      }
 909      resolve_eq_tags (INDICANTS (A68_STANDENV));
 910      resolve_eq_tags (IDENTIFIERS (A68_STANDENV));
 911      resolve_eq_tags (OPERATORS (A68_STANDENV));
 912      resolve_equivalent (&M_STRING);
 913      resolve_equivalent (&M_COMPLEX);
 914      resolve_equivalent (&M_COMPL);
 915      resolve_equivalent (&M_LONG_COMPLEX);
 916      resolve_equivalent (&M_LONG_COMPL);
 917      resolve_equivalent (&M_LONG_LONG_COMPLEX);
 918      resolve_equivalent (&M_LONG_LONG_COMPL);
 919      resolve_equivalent (&M_SEMA);
 920      resolve_equivalent (&M_PIPE);
 921  // UNION members could be resolved.
 922      absorb_unions (TOP_MOID (mod));
 923      contract_unions (TOP_MOID (mod));
 924  // FLEX INDICANT could be resolved.
 925      for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 926        if (IS_FLEX (z) && SUB (z) != NO_MOID) {
 927          if (SUB_SUB (z) != NO_MOID && IS (SUB_SUB (z), STRUCT_SYMBOL)) {
 928            MULTIPLE (z) = make_flex_multiple_struct (SUB_SUB (z), &TOP_MOID (mod), DIM (SUB (z)));
 929          }
 930        }
 931      }
 932  // See what new known modes we have generated by resolving..
 933      for (z = TOP_MOID (mod); z != STANDENV_MOID (&A68_JOB); FORWARD (z)) {
 934        MOID_T *v;
 935        for (v = NEXT (z); v != NO_MOID; FORWARD (v)) {
 936          if (prove_moid_equivalence (z, v)) {
 937            EQUIVALENT (z) = v;
 938            EQUIVALENT (v) = NO_MOID;
 939          }
 940        }
 941      }
 942  // Count the modes to check self consistency.
 943      len = nlen;
 944      for (nlen = 0, z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 945        nlen++;
 946      }
 947    }
 948    ABEND (M_STRING != M_FLEX_ROW_CHAR, ERROR_INTERNAL_CONSISTENCY, __func__);
 949  // Find out what modes contain rows.
 950    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 951      HAS_ROWS (z) = is_mode_has_row (z);
 952    }
 953  // Check flexible modes.
 954    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 955      if (IS_FLEX (z) && !IS (SUB (z), ROW_SYMBOL)) {
 956        diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
 957      }
 958    }
 959  // Check on fields in structured modes f.i. STRUCT (REAL x, INT n, REAL x) is wrong.
 960    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 961      if (IS (z, STRUCT_SYMBOL) && EQUIVALENT (z) == NO_MOID) {
 962        PACK_T *s = PACK (z);
 963        for (; s != NO_PACK; FORWARD (s)) {
 964          BOOL_T x = A68_TRUE;
 965          for (PACK_T *t = NEXT (s); t != NO_PACK && x; FORWARD (t)) {
 966            if (TEXT (s) == TEXT (t)) {
 967              diagnostic (A68_ERROR, NODE (z), ERROR_MULTIPLE_FIELD);
 968              while (NEXT (s) != NO_PACK && TEXT (NEXT (s)) == TEXT (t)) {
 969                FORWARD (s);
 970              }
 971              x = A68_FALSE;
 972            }
 973          }
 974        }
 975      }
 976    }
 977  // Various union test.
 978    for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
 979      if (IS (z, UNION_SYMBOL) && EQUIVALENT (z) == NO_MOID) {
 980        PACK_T *s = PACK (z);
 981  // Discard unions with one member.
 982        if (count_pack_members (s) == 1) {
 983          diagnostic (A68_ERROR, NODE (z), ERROR_COMPONENT_NUMBER, z);
 984        }
 985  // Discard incestuous unions with firmly related modes.
 986        for (; s != NO_PACK; FORWARD (s)) {
 987          PACK_T *t;
 988          for (t = NEXT (s); t != NO_PACK; FORWARD (t)) {
 989            if (MOID (t) != MOID (s)) {
 990              if (is_firm (MOID (s), MOID (t))) {
 991                diagnostic (A68_ERROR, NODE (z), ERROR_COMPONENT_RELATED, z);
 992              }
 993            }
 994          }
 995        }
 996  // Discard incestuous unions with firmly related subsets.
 997        for (s = PACK (z); s != NO_PACK; FORWARD (s)) {
 998          MOID_T *n = depref_completely (MOID (s));
 999          if (IS (n, UNION_SYMBOL) && is_subset (n, z, NO_DEFLEXING)) {
1000            diagnostic (A68_ERROR, NODE (z), ERROR_SUBSET_RELATED, z, n);
1001          }
1002        }
1003      }
1004    }
1005  // Wrap up and exit.
1006    free_postulate_list (A68 (top_postulate), NO_POSTULATE);
1007    A68 (top_postulate) = NO_POSTULATE;
1008  }
1009  
1010  //! @brief Make list of all modes in the program.
1011  
1012  void make_moid_list (MODULE_T * mod)
1013  {
1014    BOOL_T cont = A68_TRUE;
1015  // Collect modes from the syntax tree.
1016    reset_moid_tree (TOP_NODE (mod));
1017    get_modes_from_tree (TOP_NODE (mod), STOP);
1018    get_mode_from_proc_var_declarations_tree (TOP_NODE (mod));
1019  // Connect indicants to their declarers.
1020    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1021      if (IS (z, INDICANT)) {
1022        NODE_T *u = NODE (z);
1023        ABEND (NEXT (u) == NO_NODE, ERROR_INTERNAL_CONSISTENCY, __func__);
1024        ABEND (NEXT_NEXT (u) == NO_NODE, ERROR_INTERNAL_CONSISTENCY, __func__);
1025        ABEND (MOID (NEXT_NEXT (u)) == NO_MOID, ERROR_INTERNAL_CONSISTENCY, __func__);
1026        EQUIVALENT (z) = MOID (NEXT_NEXT (u));
1027      }
1028    }
1029  // Checks on wrong declarations.
1030    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1031      USE (z) = A68_FALSE;
1032    }
1033    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1034      if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) {
1035        if (!is_well_formed (z, EQUIVALENT (z), A68_FALSE, A68_FALSE, A68_TRUE)) {
1036          diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
1037          cont = A68_FALSE;
1038        }
1039      }
1040    }
1041    for (MOID_T *z = TOP_MOID (mod); cont && z != NO_MOID; FORWARD (z)) {
1042      if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) {
1043        ;
1044      } else if (NODE (z) != NO_NODE) {
1045        if (!is_well_formed (NO_MOID, z, A68_FALSE, A68_FALSE, A68_TRUE)) {
1046          diagnostic (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
1047        }
1048      }
1049    }
1050    for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
1051      ABEND (USE (z), ERROR_INTERNAL_CONSISTENCY, __func__);
1052    }
1053    if (ERROR_COUNT (mod) != 0) {
1054      return;
1055    }
1056    compute_derived_modes (mod);
1057    init_postulates ();
1058  }
     


© 2002-2025 J.M. van der Veer (jmvdveer@xs4all.nl)