parser-extract.c

     
   1  //! @file parser-extract.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-2023 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  //! Extract tags from phrases.
  25  
  26  #include "a68g.h"
  27  #include "a68g-parser.h"
  28  
  29  // This is part of the bottom-up parser.
  30  //
  31  // Here is a set of routines that gather definitions from phrases.
  32  // This way we can apply tags before defining them.
  33  // These routines do not look very elegant as they have to scan through all
  34  // kind of symbols to find a pattern that they recognise.
  35  
  36  //! @brief Insert alt equals symbol.
  37  
  38  void insert_alt_equals (NODE_T * p)
  39  {
  40    NODE_T *q = new_node ();
  41    *q = *p;
  42    INFO (q) = new_node_info ();
  43    *INFO (q) = *INFO (p);
  44    GINFO (q) = new_genie_info ();
  45    *GINFO (q) = *GINFO (p);
  46    ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
  47    NSYMBOL (q) = TEXT (add_token (&A68 (top_token), "="));
  48    NEXT (p) = q;
  49    PREVIOUS (q) = p;
  50    if (NEXT (q) != NO_NODE) {
  51      PREVIOUS (NEXT (q)) = q;
  52    }
  53  }
  54  
  55  //! @brief Detect redefined keyword.
  56  
  57  void detect_redefined_keyword (NODE_T * p, int construct)
  58  {
  59    if (p != NO_NODE && whether (p, KEYWORD, EQUALS_SYMBOL, STOP)) {
  60      diagnostic (A68_SYNTAX_ERROR, p, ERROR_REDEFINED_KEYWORD, NSYMBOL (p), construct);
  61    }
  62  }
  63  
  64  //! @brief Skip anything until a comma, semicolon or EXIT is found.
  65  
  66  NODE_T *skip_unit (NODE_T * p)
  67  {
  68    for (; p != NO_NODE; FORWARD (p)) {
  69      if (IS (p, COMMA_SYMBOL)) {
  70        return p;
  71      } else if (IS (p, SEMI_SYMBOL)) {
  72        return p;
  73      } else if (IS (p, EXIT_SYMBOL)) {
  74        return p;
  75      }
  76    }
  77    return NO_NODE;
  78  }
  79  
  80  //! @brief Attribute of entry in symbol table.
  81  
  82  int find_tag_definition (TABLE_T * table, char *name)
  83  {
  84    if (table != NO_TABLE) {
  85      int ret = 0;
  86      TAG_T *s;
  87      BOOL_T found;
  88      found = A68_FALSE;
  89      for (s = INDICANTS (table); s != NO_TAG && !found; FORWARD (s)) {
  90        if (NSYMBOL (NODE (s)) == name) {
  91          ret += INDICANT;
  92          found = A68_TRUE;
  93        }
  94      }
  95      found = A68_FALSE;
  96      for (s = OPERATORS (table); s != NO_TAG && !found; FORWARD (s)) {
  97        if (NSYMBOL (NODE (s)) == name) {
  98          ret += OPERATOR;
  99          found = A68_TRUE;
 100        }
 101      }
 102      if (ret == 0) {
 103        return find_tag_definition (PREVIOUS (table), name);
 104      } else {
 105        return ret;
 106      }
 107    } else {
 108      return 0;
 109    }
 110  }
 111  
 112  //! @brief Fill in whether bold tag is operator or indicant.
 113  
 114  void elaborate_bold_tags (NODE_T * p)
 115  {
 116    NODE_T *q;
 117    for (q = p; q != NO_NODE; FORWARD (q)) {
 118      if (IS (q, BOLD_TAG)) {
 119        switch (find_tag_definition (TABLE (q), NSYMBOL (q))) {
 120        case 0:
 121          {
 122            diagnostic (A68_SYNTAX_ERROR, q, ERROR_UNDECLARED_TAG);
 123            break;
 124          }
 125        case INDICANT:
 126          {
 127            ATTRIBUTE (q) = INDICANT;
 128            break;
 129          }
 130        case OPERATOR:
 131          {
 132            ATTRIBUTE (q) = OPERATOR;
 133            break;
 134          }
 135        }
 136      }
 137    }
 138  }
 139  
 140  //! @brief Skip declarer, or argument pack and declarer.
 141  
 142  NODE_T *skip_pack_declarer (NODE_T * p)
 143  {
 144  // Skip () REF [] REF FLEX [] [] ...
 145    while (p != NO_NODE && (is_one_of (p, SUB_SYMBOL, OPEN_SYMBOL, REF_SYMBOL, FLEX_SYMBOL, SHORT_SYMBOL, LONG_SYMBOL, STOP))) {
 146      FORWARD (p);
 147    }
 148  // Skip STRUCT (), UNION () or PROC [()].
 149    if (p != NO_NODE && (is_one_of (p, STRUCT_SYMBOL, UNION_SYMBOL, STOP))) {
 150      return NEXT (p);
 151    } else if (p != NO_NODE && IS (p, PROC_SYMBOL)) {
 152      return skip_pack_declarer (NEXT (p));
 153    } else {
 154      return p;
 155    }
 156  }
 157  
 158  //! @brief Search MODE A = .., B = .. and store indicants.
 159  
 160  void extract_indicants (NODE_T * p)
 161  {
 162    NODE_T *q = p;
 163    while (q != NO_NODE) {
 164      if (IS (q, MODE_SYMBOL)) {
 165        BOOL_T siga = A68_TRUE;
 166        do {
 167          FORWARD (q);
 168          detect_redefined_keyword (q, MODE_DECLARATION);
 169          if (whether (q, BOLD_TAG, EQUALS_SYMBOL, STOP)) {
 170  // Store in the symbol table, but also in the moid list.
 171  // Position of definition (q) connects to this lexical level! 
 172            ASSERT (add_tag (TABLE (p), INDICANT, q, NO_MOID, STOP) != NO_TAG);
 173            ASSERT (add_mode (&TOP_MOID (&A68_JOB), INDICANT, 0, q, NO_MOID, NO_PACK) != NO_MOID);
 174            ATTRIBUTE (q) = DEFINING_INDICANT;
 175            FORWARD (q);
 176            ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
 177            q = skip_pack_declarer (NEXT (q));
 178            FORWARD (q);
 179          } else {
 180            siga = A68_FALSE;
 181          }
 182        } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
 183      } else {
 184        FORWARD (q);
 185      }
 186    }
 187  }
 188  
 189  #define GET_PRIORITY(q, k)\
 190    errno=0;\
 191    (k) = atoi (NSYMBOL (q));\
 192    if (errno != 0) {\
 193      diagnostic (A68_SYNTAX_ERROR, (q), ERROR_INVALID_PRIORITY);\
 194      (k) = MAX_PRIORITY;\
 195    } else if ((k) < 1 || (k) > MAX_PRIORITY) {\
 196      diagnostic (A68_SYNTAX_ERROR, (q), ERROR_INVALID_PRIORITY);\
 197      (k) = MAX_PRIORITY;\
 198    }
 199  
 200  //! @brief Search PRIO X = .., Y = .. and store priorities.
 201  
 202  void extract_priorities (NODE_T * p)
 203  {
 204    NODE_T *q = p;
 205    while (q != NO_NODE) {
 206      if (IS (q, PRIO_SYMBOL)) {
 207        BOOL_T siga = A68_TRUE;
 208        do {
 209          FORWARD (q);
 210          detect_redefined_keyword (q, PRIORITY_DECLARATION);
 211  // An operator tag like ++ or && gives strange errors so we catch it here.
 212          if (whether (q, OPERATOR, OPERATOR, STOP)) {
 213            int k;
 214            NODE_T *y = q;
 215            diagnostic (A68_SYNTAX_ERROR, q, ERROR_INVALID_OPERATOR_TAG);
 216            ATTRIBUTE (q) = DEFINING_OPERATOR;
 217  // Remove one superfluous operator, and hope it was only one.           .
 218            NEXT (q) = NEXT_NEXT (q);
 219            PREVIOUS (NEXT (q)) = q;
 220            FORWARD (q);
 221            ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
 222            FORWARD (q);
 223            GET_PRIORITY (q, k);
 224            ATTRIBUTE (q) = PRIORITY;
 225            ASSERT (add_tag (TABLE (p), PRIO_SYMBOL, y, NO_MOID, k) != NO_TAG);
 226            FORWARD (q);
 227          } else if (whether (q, OPERATOR, EQUALS_SYMBOL, INT_DENOTATION, STOP) || whether (q, EQUALS_SYMBOL, EQUALS_SYMBOL, INT_DENOTATION, STOP)) {
 228            int k;
 229            NODE_T *y = q;
 230            ATTRIBUTE (q) = DEFINING_OPERATOR;
 231            FORWARD (q);
 232            ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
 233            FORWARD (q);
 234            GET_PRIORITY (q, k);
 235            ATTRIBUTE (q) = PRIORITY;
 236            ASSERT (add_tag (TABLE (p), PRIO_SYMBOL, y, NO_MOID, k) != NO_TAG);
 237            FORWARD (q);
 238          } else if (whether (q, BOLD_TAG, IDENTIFIER, STOP)) {
 239            siga = A68_FALSE;
 240          } else if (whether (q, BOLD_TAG, EQUALS_SYMBOL, INT_DENOTATION, STOP)) {
 241            int k;
 242            NODE_T *y = q;
 243            ATTRIBUTE (q) = DEFINING_OPERATOR;
 244            FORWARD (q);
 245            ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
 246            FORWARD (q);
 247            GET_PRIORITY (q, k);
 248            ATTRIBUTE (q) = PRIORITY;
 249            ASSERT (add_tag (TABLE (p), PRIO_SYMBOL, y, NO_MOID, k) != NO_TAG);
 250            FORWARD (q);
 251          } else if (whether (q, BOLD_TAG, INT_DENOTATION, STOP) || whether (q, OPERATOR, INT_DENOTATION, STOP) || whether (q, EQUALS_SYMBOL, INT_DENOTATION, STOP)) {
 252  // The scanner cannot separate operator and "=" sign so we do this here.
 253            int len = (int) strlen (NSYMBOL (q));
 254            if (len > 1 && NSYMBOL (q)[len - 1] == '=') {
 255              int k;
 256              NODE_T *y = q;
 257              char *sym = (char *) get_temp_heap_space ((size_t) (len + 1));
 258              bufcpy (sym, NSYMBOL (q), len + 1);
 259              sym[len - 1] = NULL_CHAR;
 260              NSYMBOL (q) = TEXT (add_token (&A68 (top_token), sym));
 261              if (len > 2 && NSYMBOL (q)[len - 2] == ':' && NSYMBOL (q)[len - 3] != '=') {
 262                diagnostic (A68_SYNTAX_ERROR, q, ERROR_OPERATOR_INVALID_END);
 263              }
 264              ATTRIBUTE (q) = DEFINING_OPERATOR;
 265              insert_alt_equals (q);
 266              q = NEXT_NEXT (q);
 267              GET_PRIORITY (q, k);
 268              ATTRIBUTE (q) = PRIORITY;
 269              ASSERT (add_tag (TABLE (p), PRIO_SYMBOL, y, NO_MOID, k) != NO_TAG);
 270              FORWARD (q);
 271            } else {
 272              siga = A68_FALSE;
 273            }
 274          } else {
 275            siga = A68_FALSE;
 276          }
 277        } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
 278      } else {
 279        FORWARD (q);
 280      }
 281    }
 282  }
 283  
 284  //! @brief Search OP [( .. ) ..] X = .., Y = .. and store operators.
 285  
 286  void extract_operators (NODE_T * p)
 287  {
 288    NODE_T *q = p;
 289    while (q != NO_NODE) {
 290      if (!IS (q, OP_SYMBOL)) {
 291        FORWARD (q);
 292      } else {
 293        BOOL_T siga = A68_TRUE;
 294  // Skip operator plan.
 295        if (NEXT (q) != NO_NODE && IS (NEXT (q), OPEN_SYMBOL)) {
 296          q = skip_pack_declarer (NEXT (q));
 297        }
 298  // Sample operators.
 299        if (q != NO_NODE) {
 300          do {
 301            FORWARD (q);
 302            detect_redefined_keyword (q, OPERATOR_DECLARATION);
 303  // Unacceptable operator tags like ++ or && could give strange errors.
 304            if (whether (q, OPERATOR, OPERATOR, STOP)) {
 305              diagnostic (A68_SYNTAX_ERROR, q, ERROR_INVALID_OPERATOR_TAG);
 306              ATTRIBUTE (q) = DEFINING_OPERATOR;
 307              ASSERT (add_tag (TABLE (p), OP_SYMBOL, q, NO_MOID, STOP) != NO_TAG);
 308              NEXT (q) = NEXT_NEXT (q);   // Remove one superfluous operator, and hope it was only one
 309              PREVIOUS (NEXT (q)) = q;
 310              FORWARD (q);
 311              ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
 312              q = skip_unit (q);
 313            } else if (whether (q, OPERATOR, EQUALS_SYMBOL, STOP) || whether (q, EQUALS_SYMBOL, EQUALS_SYMBOL, STOP)) {
 314              ATTRIBUTE (q) = DEFINING_OPERATOR;
 315              ASSERT (add_tag (TABLE (p), OP_SYMBOL, q, NO_MOID, STOP) != NO_TAG);
 316              FORWARD (q);
 317              ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
 318              q = skip_unit (q);
 319            } else if (whether (q, BOLD_TAG, IDENTIFIER, STOP)) {
 320              siga = A68_FALSE;
 321            } else if (whether (q, BOLD_TAG, EQUALS_SYMBOL, STOP)) {
 322              ATTRIBUTE (q) = DEFINING_OPERATOR;
 323              ASSERT (add_tag (TABLE (p), OP_SYMBOL, q, NO_MOID, STOP) != NO_TAG);
 324              FORWARD (q);
 325              ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
 326              q = skip_unit (q);
 327            } else if (q != NO_NODE && (is_one_of (q, OPERATOR, BOLD_TAG, EQUALS_SYMBOL, STOP))) {
 328  // The scanner cannot separate operator and "=" sign so we do this here.
 329              int len = (int) strlen (NSYMBOL (q));
 330              if (len > 1 && NSYMBOL (q)[len - 1] == '=') {
 331                char *sym = (char *) get_temp_heap_space ((size_t) (len + 1));
 332                bufcpy (sym, NSYMBOL (q), len + 1);
 333                sym[len - 1] = NULL_CHAR;
 334                NSYMBOL (q) = TEXT (add_token (&A68 (top_token), sym));
 335                if (len > 2 && NSYMBOL (q)[len - 2] == ':' && NSYMBOL (q)[len - 3] != '=') {
 336                  diagnostic (A68_SYNTAX_ERROR, q, ERROR_OPERATOR_INVALID_END);
 337                }
 338                ATTRIBUTE (q) = DEFINING_OPERATOR;
 339                insert_alt_equals (q);
 340                ASSERT (add_tag (TABLE (p), OP_SYMBOL, q, NO_MOID, STOP) != NO_TAG);
 341                FORWARD (q);
 342                q = skip_unit (q);
 343              } else {
 344                siga = A68_FALSE;
 345              }
 346            } else {
 347              siga = A68_FALSE;
 348            }
 349          } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
 350        }
 351      }
 352    }
 353  }
 354  
 355  //! @brief Search and store labels.
 356  
 357  void extract_labels (NODE_T * p, int expect)
 358  {
 359    NODE_T *q;
 360  // Only handle candidate phrases as not to search indexers!.
 361    if (expect == SERIAL_CLAUSE || expect == ENQUIRY_CLAUSE || expect == SOME_CLAUSE) {
 362      for (q = p; q != NO_NODE; FORWARD (q)) {
 363        if (whether (q, IDENTIFIER, COLON_SYMBOL, STOP)) {
 364          TAG_T *z = add_tag (TABLE (p), LABEL, q, NO_MOID, LOCAL_LABEL);
 365          ATTRIBUTE (q) = DEFINING_IDENTIFIER;
 366          UNIT (z) = NO_NODE;
 367        }
 368      }
 369    }
 370  }
 371  
 372  //! @brief Search MOID x = .., y = .. and store identifiers.
 373  
 374  void extract_identities (NODE_T * p)
 375  {
 376    NODE_T *q = p;
 377    while (q != NO_NODE) {
 378      if (whether (q, DECLARER, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
 379        BOOL_T siga = A68_TRUE;
 380        do {
 381          if (whether ((FORWARD (q)), IDENTIFIER, EQUALS_SYMBOL, STOP)) {
 382            ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
 383            ATTRIBUTE (q) = DEFINING_IDENTIFIER;
 384            FORWARD (q);
 385            ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
 386            q = skip_unit (q);
 387          } else if (whether (q, IDENTIFIER, ASSIGN_SYMBOL, STOP)) {
 388  // Handle common error in ALGOL 68 programs.
 389            diagnostic (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_MIXED_DECLARATION);
 390            ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
 391            ATTRIBUTE (q) = DEFINING_IDENTIFIER;
 392            ATTRIBUTE (FORWARD (q)) = ALT_EQUALS_SYMBOL;
 393            q = skip_unit (q);
 394          } else {
 395            siga = A68_FALSE;
 396          }
 397        } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
 398      } else {
 399        FORWARD (q);
 400      }
 401    }
 402  }
 403  
 404  //! @brief Search MOID x [:= ..], y [:= ..] and store identifiers.
 405  
 406  void extract_variables (NODE_T * p)
 407  {
 408    NODE_T *q = p;
 409    while (q != NO_NODE) {
 410      if (whether (q, DECLARER, IDENTIFIER, STOP)) {
 411        BOOL_T siga = A68_TRUE;
 412        do {
 413          FORWARD (q);
 414          if (whether (q, IDENTIFIER, STOP)) {
 415            if (whether (q, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
 416  // Handle common error in ALGOL 68 programs.
 417              diagnostic (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_MIXED_DECLARATION);
 418              ATTRIBUTE (NEXT (q)) = ASSIGN_SYMBOL;
 419            }
 420            ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
 421            ATTRIBUTE (q) = DEFINING_IDENTIFIER;
 422            q = skip_unit (q);
 423          } else {
 424            siga = A68_FALSE;
 425          }
 426        } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
 427      } else {
 428        FORWARD (q);
 429      }
 430    }
 431  }
 432  
 433  //! @brief Search PROC x = .., y = .. and stores identifiers.
 434  
 435  void extract_proc_identities (NODE_T * p)
 436  {
 437    NODE_T *q = p;
 438    while (q != NO_NODE) {
 439      if (whether (q, PROC_SYMBOL, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
 440        BOOL_T siga = A68_TRUE;
 441        do {
 442          FORWARD (q);
 443          if (whether (q, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
 444            TAG_T *t = add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER);
 445            IN_PROC (t) = A68_TRUE;
 446            ATTRIBUTE (q) = DEFINING_IDENTIFIER;
 447            ATTRIBUTE (FORWARD (q)) = ALT_EQUALS_SYMBOL;
 448            q = skip_unit (q);
 449          } else if (whether (q, IDENTIFIER, ASSIGN_SYMBOL, STOP)) {
 450  // Handle common error in ALGOL 68 programs.
 451            diagnostic (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_MIXED_DECLARATION);
 452            ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
 453            ATTRIBUTE (q) = DEFINING_IDENTIFIER;
 454            ATTRIBUTE (FORWARD (q)) = ALT_EQUALS_SYMBOL;
 455            q = skip_unit (q);
 456          } else {
 457            siga = A68_FALSE;
 458          }
 459        } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
 460      } else {
 461        FORWARD (q);
 462      }
 463    }
 464  }
 465  
 466  //! @brief Search PROC x [:= ..], y [:= ..]; store identifiers.
 467  
 468  void extract_proc_variables (NODE_T * p)
 469  {
 470    NODE_T *q = p;
 471    while (q != NO_NODE) {
 472      if (whether (q, PROC_SYMBOL, IDENTIFIER, STOP)) {
 473        BOOL_T siga = A68_TRUE;
 474        do {
 475          FORWARD (q);
 476          if (whether (q, IDENTIFIER, ASSIGN_SYMBOL, STOP)) {
 477            ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
 478            ATTRIBUTE (q) = DEFINING_IDENTIFIER;
 479            q = skip_unit (FORWARD (q));
 480          } else if (whether (q, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
 481  // Handle common error in ALGOL 68 programs.
 482            diagnostic (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_MIXED_DECLARATION);
 483            ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
 484            ATTRIBUTE (q) = DEFINING_IDENTIFIER;
 485            ATTRIBUTE (FORWARD (q)) = ASSIGN_SYMBOL;
 486            q = skip_unit (q);
 487          } else {
 488            siga = A68_FALSE;
 489          }
 490        } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
 491      } else {
 492        FORWARD (q);
 493      }
 494    }
 495  }
 496  
 497  //! @brief Schedule gathering of definitions in a phrase.
 498  
 499  void extract_declarations (NODE_T * p)
 500  {
 501    NODE_T *q;
 502  // Get definitions so we know what is defined in this range.
 503    extract_identities (p);
 504    extract_variables (p);
 505    extract_proc_identities (p);
 506    extract_proc_variables (p);
 507  // By now we know whether "=" is an operator or not.
 508    for (q = p; q != NO_NODE; FORWARD (q)) {
 509      if (IS (q, EQUALS_SYMBOL)) {
 510        ATTRIBUTE (q) = OPERATOR;
 511      } else if (IS (q, ALT_EQUALS_SYMBOL)) {
 512        ATTRIBUTE (q) = EQUALS_SYMBOL;
 513      }
 514    }
 515  // Get qualifiers.
 516    for (q = p; q != NO_NODE; FORWARD (q)) {
 517      if (whether (q, LOC_SYMBOL, DECLARER, DEFINING_IDENTIFIER, STOP)) {
 518        make_sub (q, q, QUALIFIER);
 519      }
 520      if (whether (q, HEAP_SYMBOL, DECLARER, DEFINING_IDENTIFIER, STOP)) {
 521        make_sub (q, q, QUALIFIER);
 522      }
 523      if (whether (q, NEW_SYMBOL, DECLARER, DEFINING_IDENTIFIER, STOP)) {
 524        make_sub (q, q, QUALIFIER);
 525      }
 526      if (whether (q, LOC_SYMBOL, PROC_SYMBOL, DEFINING_IDENTIFIER, STOP)) {
 527        make_sub (q, q, QUALIFIER);
 528      }
 529      if (whether (q, HEAP_SYMBOL, PROC_SYMBOL, DEFINING_IDENTIFIER, STOP)) {
 530        make_sub (q, q, QUALIFIER);
 531      }
 532      if (whether (q, NEW_SYMBOL, PROC_SYMBOL, DEFINING_IDENTIFIER, STOP)) {
 533        make_sub (q, q, QUALIFIER);
 534      }
 535    }
 536  // Give priorities to operators.
 537    for (q = p; q != NO_NODE; FORWARD (q)) {
 538      if (IS (q, OPERATOR)) {
 539        if (find_tag_global (TABLE (q), OP_SYMBOL, NSYMBOL (q))) {
 540          TAG_T *s = find_tag_global (TABLE (q), PRIO_SYMBOL, NSYMBOL (q));
 541          if (s != NO_TAG) {
 542            PRIO (INFO (q)) = PRIO (s);
 543          } else {
 544            PRIO (INFO (q)) = 0;
 545          }
 546        } else {
 547          diagnostic (A68_SYNTAX_ERROR, q, ERROR_UNDECLARED_TAG);
 548          PRIO (INFO (q)) = 1;
 549        }
 550      }
 551    }
 552  }