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