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 }