1 /**
2 @file syntax.c
3 @author J. Marcel van der Veer
4 @brief Hand-coded Algol 68 scanner and parser.
5 
6 @section Copyright
7 
8 This file is part of Algol 68 Genie - an Algol 68 compiler-interpreter.
9 Copyright 2001-2016 J. Marcel van der Veer <algol68g@xs4all.nl>.
10 
11 @section License
12 
13 This program is free software; you can redistribute it and/or modify it under
14 the terms of the GNU General Public License as published by the Free Software
15 Foundation; either version 3 of the License, or (at your option) any later
16 version.
17 
18 This program is distributed in the hope that it will be useful, but WITHOUT ANY
19 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
20 PARTICULAR PURPOSE. See the GNU General Public License for more details.
21 
22 You should have received a copy of the GNU General Public License along with
23 this program. If not, see <http://www.gnu.org/licenses/>.
24 
25 @section Description
26 
27 Algol 68 grammar is defined as a two level (Van Wijngaarden) grammar that
28 incorporates, as syntactical rules, the "semantical" rules in
29 other languages. Examples are correct use of symbols, modes and scope.
30 That is why so much functionality is in the "syntax.c" file. In fact, all
31 this material constitutes an effective "Algol 68 VW parser". This pragmatic
32 approach was chosen since in the early days of Algol 68, many "ab initio"
33 implementations failed.
34 
35 This is a Mailloux-type parser, in the sense that it scans a "phrase" for
36 definitions before it starts parsing, and therefore allows for tags to be used
37 before they are defined, which gives some freedom in top-down programming.
38 In 2011, FLACC documentation became available again. This documentation
39 suggests that the set-up of this parser resembles that of FLACC, which
40 supports the view that this is a Mailloux-type parser.
41 
42 First part in this file is the scanner. The source file is read,
43 is tokenised, and if needed a refinement preprocessor elaborates a stepwise
44 refined program. The result is a linear list of tokens that is input for the
45 parser, that will transform the linear list into a syntax tree.
46 
47 Algol68G tokenises all symbols before the bottom-up parser is invoked.
48 This means that scanning does not use information from the parser.
49 The scanner does of course do some rudimentary parsing. Format texts can have
50 enclosed clauses in them, so we record information in a stack as to know
51 what is being scanned. Also, the refinement preprocessor implements a
52 (trivial) grammar.
53 
54 The scanner supports two stropping regimes: bold and quote. Examples of both:
55 
56        bold stropping: BEGIN INT i = 1, j = 1; print (i + j) END
57 
58        quote stropping: 'BEGIN' 'INT' I = 1, J = 1; PRINT (I + J) 'END'
59 
60 Quote stropping was used frequently in the (excusez-le-mot) punch-card age.
61 Hence, bold stropping is the default. There also existed point stropping, but
62 that has not been implemented here.
63 
64 Next part of the parser is a recursive-descent type to check parenthesis.
65 Also a first set-up is made of symbol tables, needed by the bottom-up parser.
66 Next part is the bottom-up parser, that parses without knowing about modes while
67 parsing and reducing. It can therefore not exchange "[]" with "()" as was
68 blessed by the Revised Report. This is solved by treating CALL and SLICE as
69 equivalent for the moment and letting the mode checker sort it out later.
70 
71 Parsing progresses in various phases to avoid spurious diagnostics from a
72 recovering parser. Every phase "tightens" the grammar more.
73 An error in any phase makes the parser quit when that phase ends.
74 The parser is forgiving in case of superfluous semicolons.
75 
76 So those are the parser phases:
77 
78  (1) Parenthesis are checked to see whether they match. Then, a top-down
79      parser determines the basic-block structure of the program
80      so symbol tables can be set up that the bottom-up parser will consult
81      as you can define things before they are applied.
82 
83  (2) A bottom-up parser resolves the structure of the program.
84 
85  (3) After the symbol tables have been finalised, a small rearrangement of the
86      tree may be required where JUMPs have no GOTO. This leads to the
87      non-standard situation that JUMPs without GOTO can have the syntactic
88      position of a PRIMARY, SECONDARY or TERTIARY. The bottom-up parser also
89      does not check VICTAL correctness of declarers. This is done separately.
90      Also structure of format texts is checked separately.
91 
92 The parser sets up symbol tables and populates them as far as needed to parse
93 the source. After the bottom-up parser terminates succesfully, the symbol tables
94 are completed.
95 
96  (4) Next, modes are collected and rules for well-formedness and structural
97      equivalence are applied. Then the symbol-table is completed now moids are
98      all known.
99 
100  (5) Next phases are the mode checker and coercion inserter. The syntax tree is
101      traversed to determine and check all modes, and to select operators. Then
102      the tree is traversed again to insert coercions.
103 
104  (6) A static scope checker detects where objects are transported out of scope.
105      At run time, a dynamic scope checker will check that what the static scope
106      checker cannot see.
107 
108 With respect to the mode checker: Algol 68 contexts are SOFT, WEAK, MEEK, FIRM
109 and STRONG. These contexts are increasing in strength:
110 
111   SOFT: Deproceduring
112 
113   WEAK: Dereferencing to REF [] or REF STRUCT
114 
115   MEEK: Deproceduring and dereferencing
116 
117   FIRM: MEEK followed by uniting
118 
119   STRONG: FIRM followed by rowing, widening or voiding
120 
121 Furthermore you will see in this file next switches:
122 
123 (1) FORCE_DEFLEXING allows assignment compatibility between FLEX and non FLEX
124 rows. This can only be the case when there is no danger of altering bounds of a
125 non FLEX row.
126 
127 (2) ALIAS_DEFLEXING prohibits aliasing a FLEX row to a non FLEX row (vice versa
128 is no problem) so that one cannot alter the bounds of a non FLEX row by
129 aliasing it to a FLEX row. This is particularly the case when passing names as
130 parameters to procedures:
131 
132    PROC x = (REF STRING s) VOID: ..., PROC y = (REF [] CHAR c) VOID: ...;
133 
134    x (LOC STRING);    # OK #
135 
136    x (LOC [10] CHAR); # Not OK, suppose x changes bounds of s! #
137 
138    y (LOC STRING);    # OK #
139 
140    y (LOC [10] CHAR); # OK #
141 
142 (3) SAFE_DEFLEXING sets FLEX row apart from non FLEX row. This holds for names,
143 not for values, so common things are not rejected, for instance
144 
145    STRING x = read string;
146 
147    [] CHAR y = read string
148 
149 (4) NO_DEFLEXING sets FLEX row apart from non FLEX row.
150 
151 Finally, a static scope checker inspects the source. Note that Algol 68 also
152 needs dynamic scope checking. This phase concludes the parser.
153 **/
154 
155 #if defined HAVE_CONFIG_H
156 #include "a68g-config.h"
157 #endif
158 
159 #include "a68g.h"
160 
161 static MOID_T *get_mode_from_declarer (NODE_T *);
162 
163 typedef struct TUPLE_T TUPLE_T;
164 typedef struct SCOPE_T SCOPE_T;
165 
166 struct TUPLE_T
167 {
168   int level;
169   BOOL_T transient;
170 };
171 
172 struct SCOPE_T
173 {
174   NODE_T *where;
175   TUPLE_T tuple;
176   SCOPE_T *next;
177 };
178 
179 enum
180 { NOT_TRANSIENT = 0, TRANSIENT };
181 
182 static void gather_scopes_for_youngest (NODE_T *, SCOPE_T **);
183 static void scope_statement (NODE_T *, SCOPE_T **);
184 static void scope_enclosed_clause (NODE_T *, SCOPE_T **);
185 static void scope_formula (NODE_T *, SCOPE_T **);
186 static void scope_routine_text (NODE_T *, SCOPE_T **);
187 TAG_T *error_tag;
188 
189 static SOID_T *top_soid_list = NO_SOID;
190 
191 static BOOL_T basic_coercions (MOID_T *, MOID_T *, int, int);
192 static BOOL_T is_coercible (MOID_T *, MOID_T *, int, int);
193 static BOOL_T is_nonproc (MOID_T *);
194 static void mode_check_enclosed (NODE_T *, SOID_T *, SOID_T *);
195 static void mode_check_unit (NODE_T *, SOID_T *, SOID_T *);
196 static void mode_check_formula (NODE_T *, SOID_T *, SOID_T *);
197 static void coerce_enclosed (NODE_T *, SOID_T *);
198 static void coerce_operand (NODE_T *, SOID_T *);
199 static void coerce_formula (NODE_T *, SOID_T *);
200 static void coerce_unit (NODE_T *, SOID_T *);
201 
202 #define DEPREF A68_TRUE
203 #define NO_DEPREF A68_FALSE
204 
205 #define IF_MODE_IS_WELL(n) (! ((n) == MODE (ERROR) || (n) == MODE (UNDEFINED)))
206 #define INSERT_COERCIONS(n, p, q) make_strong ((n), (p), MOID (q))
207 
208 #define STOP_CHAR 127
209 
210 #define IN_PRELUDE(p) (LINE_NUMBER (p) <= 0)
211 #define EOL(c) ((c) == NEWLINE_CHAR || (c) == NULL_CHAR)
212 
213 static BOOL_T stop_scanner = A68_FALSE, read_error = A68_FALSE, no_preprocessing = A68_FALSE;
214 static char *scan_buf;
215 static int max_scan_buf_length, source_file_size;
216 static int reductions = 0;
217 static jmp_buf bottom_up_crash_exit, top_down_crash_exit;
218 
219 static BOOL_T victal_check_declarer (NODE_T *, int);
220 static NODE_T *reduce_dyadic (NODE_T *, int u);
221 static NODE_T *top_down_loop (NODE_T *);
222 static NODE_T *top_down_skip_unit (NODE_T *);
223 static void append_source_line (char *, LINE_T **, int *, char *);
224 static void elaborate_bold_tags (NODE_T *);
225 static void extract_declarations (NODE_T *);
226 static void extract_identities (NODE_T *);
227 static void extract_indicants (NODE_T *);
228 static void extract_labels (NODE_T *, int);
229 static void extract_operators (NODE_T *);
230 static void extract_priorities (NODE_T *);
231 static void extract_proc_identities (NODE_T *);
232 static void extract_proc_variables (NODE_T *);
233 static void extract_variables (NODE_T *);
234 static void ignore_superfluous_semicolons (NODE_T *);
235 static void recover_from_error (NODE_T *, int, BOOL_T);
236 static void reduce_arguments (NODE_T *);
237 static void reduce_basic_declarations (NODE_T *);
238 static void reduce_bounds (NODE_T *);
239 static void reduce_collateral_clauses (NODE_T *);
240 static void reduce_declaration_lists (NODE_T *);
241 static void reduce_declarers (NODE_T *, int);
242 static void reduce_enclosed_clauses (NODE_T *, int);
243 static void reduce_enquiry_clauses (NODE_T *);
244 static void reduce_erroneous_units (NODE_T *);
245 static void reduce_format_texts (NODE_T *);
246 static void reduce_formulae (NODE_T *);
247 static void reduce_generic_arguments (NODE_T *);
248 static void reduce_primaries (NODE_T *, int);
249 static void reduce_primary_parts (NODE_T *, int);
250 static void reduce_right_to_left_constructs (NODE_T * q);
251 static void reduce_secondaries (NODE_T *);
252 static void reduce_serial_clauses (NODE_T *);
253 static void reduce_branch (NODE_T *, int);
254 static void reduce_tertiaries (NODE_T *);
255 static void reduce_units (NODE_T *);
256 static void reduce (NODE_T *, void (*)(NODE_T *), BOOL_T *, ...);
257 
258 /* Standard environ */
259 
260 static char *bold_prelude_start[] = {
261   "BEGIN MODE DOUBLE = LONG REAL, QUAD = LONG LONG REAL;",
262   "      start: commence:",
263   "      BEGIN",
264   NO_TEXT
265 };
266 
267 static char *bold_postlude[] = {
268   "      END;",
269   "      stop: abort: halt: SKIP",
270   "END",
271   NO_TEXT
272 };
273 
274 static char *quote_prelude_start[] = {
275   "'BEGIN' 'MODE' 'DOUBLE' = 'LONG' 'REAL'," "               'QUAD' = 'LONG' 'LONG' 'REAL'," "               'DEVICE' = 'FILE'," "               'TEXT' = 'STRING';" "        START: COMMENCE:" "        'BEGIN'",
276   NO_TEXT
277 };
278 
279 static char *quote_postlude[] = {
280   "     'END';",
281   "     STOP: ABORT: HALT: 'SKIP'",
282   "'END'",
283   NO_TEXT
284 };
285 
286 /**
287 @brief Is_ref_refety_flex.
288 @param m Mode under test.
289 @return See brief description.
290 **/
291 
292 static BOOL_T
is_ref_refety_flex(MOID_T * m)293 is_ref_refety_flex (MOID_T * m)
294 {
295   if (IS_REF_FLEX (m)) {
296     return (A68_TRUE);
297   } else if (IS (m, REF_SYMBOL)) {
298     return (is_ref_refety_flex (SUB (m)));
299   } else {
300     return (A68_FALSE);
301   }
302 }
303 
304 /**
305 @brief Count pictures.
306 @param p Node in syntax tree.
307 @param k Counter.
308 **/
309 
310 static void
count_pictures(NODE_T * p,int * k)311 count_pictures (NODE_T * p, int *k)
312 {
313   for (; p != NO_NODE; FORWARD (p)) {
314     if (IS (p, PICTURE)) {
315       (*k)++;
316     }
317     count_pictures (SUB (p), k);
318   }
319 }
320 
321 /**
322 @brief Count number of operands in operator parameter list.
323 @param p Node in syntax tree.
324 @return See brief description.
325 **/
326 
327 static int
count_operands(NODE_T * p)328 count_operands (NODE_T * p)
329 {
330   if (p != NO_NODE) {
331     if (IS (p, DECLARER)) {
332       return (count_operands (NEXT (p)));
333     } else if (IS (p, COMMA_SYMBOL)) {
334       return (1 + count_operands (NEXT (p)));
335     } else {
336       return (count_operands (NEXT (p)) + count_operands (SUB (p)));
337     }
338   } else {
339     return (0);
340   }
341 }
342 
343 /**
344 @brief Count formal bounds in declarer in tree.
345 @param p Node in syntax tree.
346 @return See brief description.
347 **/
348 
349 static int
count_formal_bounds(NODE_T * p)350 count_formal_bounds (NODE_T * p)
351 {
352   if (p == NO_NODE) {
353     return (0);
354   } else {
355     if (IS (p, COMMA_SYMBOL)) {
356       return (1);
357     } else {
358       return (count_formal_bounds (NEXT (p)) + count_formal_bounds (SUB (p)));
359     }
360   }
361 }
362 
363 /**
364 @brief Count bounds in declarer in tree.
365 @param p Node in syntax tree.
366 @return See brief description.
367 **/
368 
369 static int
count_bounds(NODE_T * p)370 count_bounds (NODE_T * p)
371 {
372   if (p == NO_NODE) {
373     return (0);
374   } else {
375     if (IS (p, BOUND)) {
376       return (1 + count_bounds (NEXT (p)));
377     } else {
378       return (count_bounds (NEXT (p)) + count_bounds (SUB (p)));
379     }
380   }
381 }
382 
383 /**
384 @brief Count number of SHORTs or LONGs.
385 @param p Node in syntax tree.
386 @return See brief description.
387 **/
388 
389 static int
count_sizety(NODE_T * p)390 count_sizety (NODE_T * p)
391 {
392   if (p == NO_NODE) {
393     return (0);
394   } else if (IS (p, LONGETY)) {
395     return (count_sizety (SUB (p)) + count_sizety (NEXT (p)));
396   } else if (IS (p, SHORTETY)) {
397     return (count_sizety (SUB (p)) + count_sizety (NEXT (p)));
398   } else if (IS (p, LONG_SYMBOL)) {
399     return (1);
400   } else if (IS (p, SHORT_SYMBOL)) {
401     return (-1);
402   } else {
403     return (0);
404   }
405 }
406 
407 /**
408 @brief Count moids in a pack.
409 @param u Pack.
410 @return See brief description.
411 **/
412 
413 int
count_pack_members(PACK_T * u)414 count_pack_members (PACK_T * u)
415 {
416   int k = 0;
417   for (; u != NO_PACK; FORWARD (u)) {
418     k++;
419   }
420   return (k);
421 }
422 
423 /**
424 @brief Replace a mode by its equivalent mode.
425 @param m Mode to replace.
426 **/
427 
428 static void
resolve_equivalent(MOID_T ** m)429 resolve_equivalent (MOID_T ** m)
430 {
431   while ((*m) != NO_MOID && EQUIVALENT ((*m)) != NO_MOID && (*m) != EQUIVALENT (*m)) {
432     (*m) = EQUIVALENT (*m);
433   }
434 }
435 
436 /**
437 @brief Save scanner state, for character look-ahead.
438 @param ref_l Source line.
439 @param ref_s Position in source line text.
440 @param ch Last scanned character.
441 **/
442 
443 static void
save_state(LINE_T * ref_l,char * ref_s,char ch)444 save_state (LINE_T * ref_l, char *ref_s, char ch)
445 {
446   SCAN_STATE_L (&program) = ref_l;
447   SCAN_STATE_S (&program) = ref_s;
448   SCAN_STATE_C (&program) = ch;
449 }
450 
451 /**
452 @brief Restore scanner state, for character look-ahead.
453 @param ref_l Source line.
454 @param ref_s Position in source line text.
455 @param ch Last scanned character.
456 **/
457 
458 static void
restore_state(LINE_T ** ref_l,char ** ref_s,char * ch)459 restore_state (LINE_T ** ref_l, char **ref_s, char *ch)
460 {
461   *ref_l = SCAN_STATE_L (&program);
462   *ref_s = SCAN_STATE_S (&program);
463   *ch = SCAN_STATE_C (&program);
464 }
465 
466 /**************************************/
467 /* Scanner, tokenises the source code */
468 /**************************************/
469 
470 /**
471 @brief Whether ch is unworthy.
472 @param u Source line with error.
473 @param v Character in line.
474 @param ch
475 **/
476 
477 static void
unworthy(LINE_T * u,char * v,char ch)478 unworthy (LINE_T * u, char *v, char ch)
479 {
480   if (IS_PRINT (ch)) {
481     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "*%s", ERROR_UNWORTHY_CHARACTER) >= 0);
482   } else {
483     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "*%s %s", ERROR_UNWORTHY_CHARACTER, ctrl_char (ch)) >= 0);
484   }
485   scan_error (u, v, edit_line);
486 }
487 
488 /**
489 @brief Concatenate lines that terminate in '\' with next line.
490 @param top Top source line.
491 **/
492 
493 static void
concatenate_lines(LINE_T * top)494 concatenate_lines (LINE_T * top)
495 {
496   LINE_T *q;
497 /* Work from bottom backwards */
498   for (q = top; q != NO_LINE && NEXT (q) != NO_LINE; q = NEXT (q)) {
499     ;
500   }
501   for (; q != NO_LINE; BACKWARD (q)) {
502     char *z = STRING (q);
503     int len = (int) strlen (z);
504     if (len >= 2 && z[len - 2] == BACKSLASH_CHAR && z[len - 1] == NEWLINE_CHAR && NEXT (q) != NO_LINE && STRING (NEXT (q)) != NO_TEXT) {
505       z[len - 2] = NULL_CHAR;
506       len += (int) strlen (STRING (NEXT (q)));
507       z = (char *) get_fixed_heap_space ((size_t) (len + 1));
508       bufcpy (z, STRING (q), len + 1);
509       bufcat (z, STRING (NEXT (q)), len + 1);
510       STRING (NEXT (q))[0] = NULL_CHAR;
511       STRING (q) = z;
512     }
513   }
514 }
515 
516 /**
517 @brief Whether u is bold tag v, independent of stropping regime.
518 @param u Symbol under test.
519 @param v Bold symbol .
520 @return Whether u is v.
521 **/
522 
523 static BOOL_T
is_bold(char * u,char * v)524 is_bold (char *u, char *v)
525 {
526   unsigned len = (unsigned) strlen (v);
527   if (OPTION_STROPPING (&program) == QUOTE_STROPPING) {
528     if (u[0] == '\'') {
529       return ((BOOL_T) (strncmp (++u, v, len) == 0 && u[len] == '\''));
530     } else {
531       return (A68_FALSE);
532     }
533   } else {
534     return ((BOOL_T) (strncmp (u, v, len) == 0 && !IS_UPPER (u[len])));
535   }
536 }
537 
538 /**
539 @brief Skip string.
540 @param top Current source line.
541 @param ch Current character in source line.
542 @return Whether string is properly terminated.
543 **/
544 
545 static BOOL_T
skip_string(LINE_T ** top,char ** ch)546 skip_string (LINE_T ** top, char **ch)
547 {
548   LINE_T *u = *top;
549   char *v = *ch;
550   v++;
551   while (u != NO_LINE) {
552     while (v[0] != NULL_CHAR) {
553       if (v[0] == QUOTE_CHAR && v[1] != QUOTE_CHAR) {
554         *top = u;
555         *ch = &v[1];
556         return (A68_TRUE);
557       } else if (v[0] == QUOTE_CHAR && v[1] == QUOTE_CHAR) {
558         v += 2;
559       } else {
560         v++;
561       }
562     }
563     FORWARD (u);
564     if (u != NO_LINE) {
565       v = &(STRING (u)[0]);
566     } else {
567       v = NO_TEXT;
568     }
569   }
570   return (A68_FALSE);
571 }
572 
573 /**
574 @brief Skip comment.
575 @param top Current source line.
576 @param ch Current character in source line.
577 @param delim Expected terminating delimiter.
578 @return Whether comment is properly terminated.
579 **/
580 
581 static BOOL_T
skip_comment(LINE_T ** top,char ** ch,int delim)582 skip_comment (LINE_T ** top, char **ch, int delim)
583 {
584   LINE_T *u = *top;
585   char *v = *ch;
586   v++;
587   while (u != NO_LINE) {
588     while (v[0] != NULL_CHAR) {
589       if (is_bold (v, "COMMENT") && delim == BOLD_COMMENT_SYMBOL) {
590         *top = u;
591         *ch = &v[1];
592         return (A68_TRUE);
593       } else if (is_bold (v, "CO") && delim == STYLE_I_COMMENT_SYMBOL) {
594         *top = u;
595         *ch = &v[1];
596         return (A68_TRUE);
597       } else if (v[0] == '#' && delim == STYLE_II_COMMENT_SYMBOL) {
598         *top = u;
599         *ch = &v[1];
600         return (A68_TRUE);
601       } else {
602         v++;
603       }
604     }
605     FORWARD (u);
606     if (u != NO_LINE) {
607       v = &(STRING (u)[0]);
608     } else {
609       v = NO_TEXT;
610     }
611   }
612   return (A68_FALSE);
613 }
614 
615 /**
616 @brief Skip rest of pragmat.
617 @param top Current source line.
618 @param ch Current character in source line.
619 @param delim Expected terminating delimiter.
620 @param whitespace Whether other pragmat items are allowed.
621 @return Whether pragmat is properly terminated.
622 **/
623 
624 static BOOL_T
skip_pragmat(LINE_T ** top,char ** ch,int delim,BOOL_T whitespace)625 skip_pragmat (LINE_T ** top, char **ch, int delim, BOOL_T whitespace)
626 {
627   LINE_T *u = *top;
628   char *v = *ch;
629   while (u != NO_LINE) {
630     while (v[0] != NULL_CHAR) {
631       if (is_bold (v, "PRAGMAT") && delim == BOLD_PRAGMAT_SYMBOL) {
632         *top = u;
633         *ch = &v[1];
634         return (A68_TRUE);
635       } else if (is_bold (v, "PR")
636                  && delim == STYLE_I_PRAGMAT_SYMBOL) {
637         *top = u;
638         *ch = &v[1];
639         return (A68_TRUE);
640       } else {
641         if (whitespace && !IS_SPACE (v[0]) && v[0] != NEWLINE_CHAR) {
642           scan_error (u, v, ERROR_PRAGMENT);
643         } else if (IS_UPPER (v[0])) {
644 /* Skip a bold word as you may trigger on REPR, for instance .. */
645           while (IS_UPPER (v[0])) {
646             v++;
647           }
648         } else {
649           v++;
650         }
651       }
652     }
653     FORWARD (u);
654     if (u != NO_LINE) {
655       v = &(STRING (u)[0]);
656     } else {
657       v = NO_TEXT;
658     }
659   }
660   return (A68_FALSE);
661 }
662 
663 /**
664 @brief Return pointer to next token within pragmat.
665 @param top Current source line.
666 @param ch Current character in source line.
667 @return Pointer to next item, NO_TEXT if none remains.
668 **/
669 
670 static char *
get_pragmat_item(LINE_T ** top,char ** ch)671 get_pragmat_item (LINE_T ** top, char **ch)
672 {
673   LINE_T *u = *top;
674   char *v = *ch;
675   while (u != NO_LINE) {
676     while (v[0] != NULL_CHAR) {
677       if (!IS_SPACE (v[0]) && v[0] != NEWLINE_CHAR) {
678         *top = u;
679         *ch = v;
680         return (v);
681       } else {
682         v++;
683       }
684     }
685     FORWARD (u);
686     if (u != NO_LINE) {
687       v = &(STRING (u)[0]);
688     } else {
689       v = NO_TEXT;
690     }
691   }
692   return (NO_TEXT);
693 }
694 
695 /**
696 @brief Case insensitive strncmp for at most the number of chars in 'v'.
697 @param u String 1, must not be NO_TEXT.
698 @param v String 2, must not be NO_TEXT.
699 @return Alphabetic difference between 1 and 2.
700 **/
701 
702 static int
streq(char * u,char * v)703 streq (char *u, char *v)
704 {
705   int diff;
706   for (diff = 0; diff == 0 && u[0] != NULL_CHAR && v[0] != NULL_CHAR; u++, v++) {
707     diff = ((int) TO_LOWER (u[0])) - ((int) TO_LOWER (v[0]));
708   }
709   return (diff);
710 }
711 
712 /**
713 @brief Scan for next pragmat and yield first pragmat item.
714 @param top Current source line.
715 @param ch Current character in source line.
716 @param delim Expected terminating delimiter.
717 @return Pointer to next item or NO_TEXT if none remain.
718 **/
719 
720 static char *
next_preprocessor_item(LINE_T ** top,char ** ch,int * delim)721 next_preprocessor_item (LINE_T ** top, char **ch, int *delim)
722 {
723   LINE_T *u = *top;
724   char *v = *ch;
725   *delim = 0;
726   while (u != NO_LINE) {
727     while (v[0] != NULL_CHAR) {
728       LINE_T *start_l = u;
729       char *start_c = v;
730 /* STRINGs must be skipped */
731       if (v[0] == QUOTE_CHAR) {
732         SCAN_ERROR (!skip_string (&u, &v), start_l, start_c, ERROR_UNTERMINATED_STRING);
733       }
734 /* COMMENTS must be skipped */
735       else if (is_bold (v, "COMMENT")) {
736         SCAN_ERROR (!skip_comment (&u, &v, BOLD_COMMENT_SYMBOL), start_l, start_c, ERROR_UNTERMINATED_COMMENT);
737       } else if (is_bold (v, "CO")) {
738         SCAN_ERROR (!skip_comment (&u, &v, STYLE_I_COMMENT_SYMBOL), start_l, start_c, ERROR_UNTERMINATED_COMMENT);
739       } else if (v[0] == '#') {
740         SCAN_ERROR (!skip_comment (&u, &v, STYLE_II_COMMENT_SYMBOL), start_l, start_c, ERROR_UNTERMINATED_COMMENT);
741       } else if (is_bold (v, "PRAGMAT") || is_bold (v, "PR")) {
742 /* We caught a PRAGMAT */
743         char *item;
744         if (is_bold (v, "PRAGMAT")) {
745           *delim = BOLD_PRAGMAT_SYMBOL;
746           v = &v[strlen ("PRAGMAT")];
747         } else if (is_bold (v, "PR")) {
748           *delim = STYLE_I_PRAGMAT_SYMBOL;
749           v = &v[strlen ("PR")];
750         }
751         item = get_pragmat_item (&u, &v);
752         SCAN_ERROR (item == NO_TEXT, start_l, start_c, ERROR_UNTERMINATED_PRAGMAT);
753 /* Item "preprocessor" restarts preprocessing if it is off */
754         if (no_preprocessing && streq (item, "PREPROCESSOR") == 0) {
755           no_preprocessing = A68_FALSE;
756           SCAN_ERROR (!skip_pragmat (&u, &v, *delim, A68_TRUE), start_l, start_c, ERROR_UNTERMINATED_PRAGMAT);
757         }
758 /* If preprocessing is switched off, we idle to closing bracket */
759         else if (no_preprocessing) {
760           SCAN_ERROR (!skip_pragmat (&u, &v, *delim, A68_FALSE), start_l, start_c, ERROR_UNTERMINATED_PRAGMAT);
761         }
762 /* Item "nopreprocessor" stops preprocessing if it is on */
763         if (streq (item, "NOPREPROCESSOR") == 0) {
764           no_preprocessing = A68_TRUE;
765           SCAN_ERROR (!skip_pragmat (&u, &v, *delim, A68_TRUE), start_l, start_c, ERROR_UNTERMINATED_PRAGMAT);
766         }
767 /* Item "INCLUDE" includes a file */
768         else if (streq (item, "INCLUDE") == 0) {
769           *top = u;
770           *ch = v;
771           return (item);
772         }
773 /* Item "READ" includes a file */
774         else if (streq (item, "READ") == 0) {
775           *top = u;
776           *ch = v;
777           return (item);
778         }
779 /* Unrecognised item - probably options handled later by the tokeniser */
780         else {
781           SCAN_ERROR (!skip_pragmat (&u, &v, *delim, A68_FALSE), start_l, start_c, ERROR_UNTERMINATED_PRAGMAT);
782         }
783       } else if (IS_UPPER (v[0])) {
784 /* Skip a bold word as you may trigger on REPR, for instance .. */
785         while (IS_UPPER (v[0])) {
786           v++;
787         }
788       } else {
789         v++;
790       }
791     }
792     FORWARD (u);
793     if (u != NO_LINE) {
794       v = &(STRING (u)[0]);
795     } else {
796       v = NO_TEXT;
797     }
798   }
799   *top = u;
800   *ch = v;
801   return (NO_TEXT);
802 }
803 
804 /**
805 @brief Include files.
806 @param top Top source line.
807 **/
808 
809 static void
include_files(LINE_T * top)810 include_files (LINE_T * top)
811 {
812 /*
813 include_files
814 
815 syntax: PR read "filename" PR
816         PR include "filename" PR
817 
818 The file gets inserted before the line containing the pragmat. In this way
819 correct line numbers are preserved which helps diagnostics. A file that has
820 been included will not be included a second time - it will be ignored.
821 */
822   BOOL_T make_pass = A68_TRUE;
823   while (make_pass) {
824     LINE_T *s, *t, *u = top;
825     char *v = &(STRING (u)[0]);
826     make_pass = A68_FALSE;
827     RESET_ERRNO;
828     while (u != NO_LINE) {
829       int pr_lim;
830       char *item = next_preprocessor_item (&u, &v, &pr_lim);
831       LINE_T *start_l = u;
832       char *start_c = v;
833 /* Search for PR include "filename" PR */
834       if (item != NO_TEXT && (streq (item, "INCLUDE") == 0 || streq (item, "READ") == 0)) {
835         FILE_T fd;
836         int n, linum, fsize, k, bytes_read, fnwid;
837         char *fbuf, delim;
838         char fnb[BUFFER_SIZE], *fn;
839 /* Skip to filename */
840         if (streq (item, "INCLUDE") == 0) {
841           v = &v[strlen ("INCLUDE")];
842         } else {
843           v = &v[strlen ("READ")];
844         }
845         while (IS_SPACE (v[0])) {
846           v++;
847         }
848 /* Scan quoted filename */
849         SCAN_ERROR ((v[0] != QUOTE_CHAR && v[0] != '\''), start_l, start_c, ERROR_INCORRECT_FILENAME);
850         delim = (v++)[0];
851         n = 0;
852         fnb[0] = NULL_CHAR;
853 /* Scan Algol 68 string (note: "" denotes a ", while in C it concatenates).*/
854         do {
855           SCAN_ERROR (EOL (v[0]), start_l, start_c, ERROR_INCORRECT_FILENAME);
856           SCAN_ERROR (n == BUFFER_SIZE - 1, start_l, start_c, ERROR_INCORRECT_FILENAME);
857           if (v[0] == delim) {
858             while (v[0] == delim && v[1] == delim) {
859               SCAN_ERROR (n == BUFFER_SIZE - 1, start_l, start_c, ERROR_INCORRECT_FILENAME);
860               fnb[n++] = delim;
861               fnb[n] = NULL_CHAR;
862               v += 2;
863             }
864           } else if (IS_PRINT (v[0])) {
865             fnb[n++] = *(v++);
866             fnb[n] = NULL_CHAR;
867           } else {
868             SCAN_ERROR (A68_TRUE, start_l, start_c, ERROR_INCORRECT_FILENAME);
869           }
870         } while (v[0] != delim);
871 /* Insist that the pragmat is closed properly */
872         v = &v[1];
873         SCAN_ERROR (!skip_pragmat (&u, &v, pr_lim, A68_TRUE), start_l, start_c, ERROR_UNTERMINATED_PRAGMAT);
874 /* Filename valid? */
875         SCAN_ERROR (n == 0, start_l, start_c, ERROR_INCORRECT_FILENAME);
876         fnwid = (int) strlen (fnb) + 1;
877         fn = (char *) get_fixed_heap_space ((size_t) fnwid);
878         bufcpy (fn, fnb, fnwid);
879 /* Recursive include? Then *ignore* the file */
880         for (t = top; t != NO_LINE; t = NEXT (t)) {
881           if (strcmp (FILENAME (t), fn) == 0) {
882             goto search_next_pragmat;   /* Eeek! */
883           }
884         }
885 /* Access the file */
886         RESET_ERRNO;
887         fd = open (fn, O_RDONLY | O_BINARY);
888         ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "*%s \"%s\"", ERROR_SOURCE_FILE_OPEN, fn) >= 0);
889         SCAN_ERROR (fd == -1, start_l, start_c, edit_line);
890 /* Access the file */
891         RESET_ERRNO;
892         fsize = (int) lseek (fd, 0, SEEK_END);
893         ASSERT (fsize >= 0);
894         SCAN_ERROR (errno != 0, start_l, start_c, ERROR_FILE_READ);
895         fbuf = (char *) get_temp_heap_space ((unsigned) (8 + fsize));
896         RESET_ERRNO;
897         ASSERT (lseek (fd, 0, SEEK_SET) >= 0);
898         SCAN_ERROR (errno != 0, start_l, start_c, ERROR_FILE_READ);
899         RESET_ERRNO;
900         bytes_read = (int) io_read (fd, fbuf, (size_t) fsize);
901         SCAN_ERROR (errno != 0 || bytes_read != fsize, start_l, start_c, ERROR_FILE_READ);
902 /* Buffer still usable? */
903         if (fsize > max_scan_buf_length) {
904           max_scan_buf_length = fsize;
905           scan_buf = (char *) get_temp_heap_space ((unsigned) (8 + max_scan_buf_length));
906         }
907 /* Link all lines into the list */
908         linum = 1;
909         s = u;
910         t = PREVIOUS (u);
911         k = 0;
912         if (fsize == 0) {
913 /* If file is empty, insert single empty line */
914           scan_buf[0] = NEWLINE_CHAR;
915           scan_buf[1] = NULL_CHAR;
916           append_source_line (scan_buf, &t, &linum, fn);
917         } else
918           while (k < fsize) {
919             n = 0;
920             scan_buf[0] = NULL_CHAR;
921             while (k < fsize && fbuf[k] != NEWLINE_CHAR) {
922               SCAN_ERROR ((IS_CNTRL (fbuf[k]) && !IS_SPACE (fbuf[k])) || fbuf[k] == STOP_CHAR, start_l, start_c, ERROR_FILE_INCLUDE_CTRL);
923               scan_buf[n++] = fbuf[k++];
924               scan_buf[n] = NULL_CHAR;
925             }
926             scan_buf[n++] = NEWLINE_CHAR;
927             scan_buf[n] = NULL_CHAR;
928             if (k < fsize) {
929               k++;
930             }
931             append_source_line (scan_buf, &t, &linum, fn);
932           }
933 /* Conclude and go find another include directive, if any */
934         NEXT (t) = s;
935         PREVIOUS (s) = t;
936         concatenate_lines (top);
937         ASSERT (close (fd) == 0);
938         make_pass = A68_TRUE;
939       }
940     search_next_pragmat:       /* skip */ ;
941     }
942   }
943 }
944 
945 /**
946 @brief Append a source line to the internal source file.
947 @param str Text line to be appended.
948 @param ref_l Previous source line.
949 @param line_num Previous source line number.
950 @param filename Name of file being read.
951 **/
952 
953 static void
append_source_line(char * str,LINE_T ** ref_l,int * line_num,char * filename)954 append_source_line (char *str, LINE_T ** ref_l, int *line_num, char *filename)
955 {
956   LINE_T *z = new_source_line ();
957 /* Allow shell command in first line, f.i. "#!/usr/share/bin/a68g" */
958   if (*line_num == 1) {
959     if (strlen (str) >= 2 && strncmp (str, "#!", 2) == 0) {
960       ABEND (strstr (str, "run-script") != NO_TEXT, ERROR_SHELL_SCRIPT, NO_TEXT);
961       (*line_num)++;
962       return;
963     }
964   }
965 /* Link line into the chain */
966   STRING (z) = new_fixed_string (str);
967   FILENAME (z) = filename;
968   NUMBER (z) = (*line_num)++;
969   PRINT_STATUS (z) = NOT_PRINTED;
970   LIST (z) = A68_TRUE;
971   DIAGNOSTICS (z) = NO_DIAGNOSTIC;
972   NEXT (z) = NO_LINE;
973   PREVIOUS (z) = *ref_l;
974   if (TOP_LINE (&program) == NO_LINE) {
975     TOP_LINE (&program) = z;
976   }
977   if (*ref_l != NO_LINE) {
978     NEXT (*ref_l) = z;
979   }
980   *ref_l = z;
981 }
982 
983 /**
984 @brief Size of source file.
985 @return Size of file.
986 **/
987 
988 static int
get_source_size(void)989 get_source_size (void)
990 {
991   FILE_T f = FILE_SOURCE_FD (&program);
992 /* This is why WIN32 must open as "read binary" */
993   return ((int) lseek (f, 0, SEEK_END));
994 }
995 
996 /**
997 @brief Append environment source lines.
998 @param str Line to append.
999 @param ref_l Source line after which to append.
1000 @param line_num Number of source line 'ref_l'.
1001 @param name Either "prelude" or "postlude".
1002 **/
1003 
1004 static void
append_environ(char * str[],LINE_T ** ref_l,int * line_num,char * name)1005 append_environ (char *str[], LINE_T ** ref_l, int *line_num, char *name)
1006 {
1007   int k;
1008   for (k = 0; str[k] != NO_TEXT; k++) {
1009     int zero_line_num = 0;
1010     (*line_num)++;
1011     append_source_line (str[k], ref_l, &zero_line_num, name);
1012   }
1013 /*
1014   char *text = new_string (str, NO_TEXT);
1015   while (text != NO_TEXT && text[0] != NULL_CHAR) {
1016     char *car = text;
1017     char *cdr = a68g_strchr (text, '!');
1018     int zero_line_num = 0;
1019     cdr[0] = NULL_CHAR;
1020     text = &cdr[1];
1021     (*line_num)++;
1022     ASSERT (snprintf (edit_line, SNPRINTF_SIZE, "%s\n", car) >= 0);
1023     append_source_line (edit_line, ref_l, &zero_line_num, name);
1024   }
1025 */
1026 }
1027 
1028 /**
1029 @brief Read script file and make internal copy.
1030 @return Whether reading is satisfactory .
1031 **/
1032 
1033 static BOOL_T
read_script_file(void)1034 read_script_file (void)
1035 {
1036   LINE_T *ref_l = NO_LINE;
1037   int k, n, num;
1038   unsigned len;
1039   BOOL_T file_end = A68_FALSE;
1040   char filename[BUFFER_SIZE], linenum[BUFFER_SIZE];
1041   char ch, *fn, *line;
1042   char *buffer = (char *) get_temp_heap_space ((unsigned) (8 + source_file_size));
1043   FILE_T source = FILE_SOURCE_FD (&program);
1044   ABEND (source == -1, "source file not open", NO_TEXT);
1045   buffer[0] = NULL_CHAR;
1046   n = 0;
1047   len = (unsigned) (8 + source_file_size);
1048   buffer = (char *) get_temp_heap_space (len);
1049   ASSERT (lseek (source, 0, SEEK_SET) >= 0);
1050   while (!file_end) {
1051 /* Read the original file name */
1052     filename[0] = NULL_CHAR;
1053     k = 0;
1054     if (io_read (source, &ch, 1) == 0) {
1055       file_end = A68_TRUE;
1056       continue;
1057     }
1058     while (ch != NEWLINE_CHAR) {
1059       filename[k++] = ch;
1060       ASSERT (io_read (source, &ch, 1) == 1);
1061     }
1062     filename[k] = NULL_CHAR;
1063     fn = TEXT (add_token (&top_token, filename));
1064 /* Read the original file number */
1065     linenum[0] = NULL_CHAR;
1066     k = 0;
1067     ASSERT (io_read (source, &ch, 1) == 1);
1068     while (ch != NEWLINE_CHAR) {
1069       linenum[k++] = ch;
1070       ASSERT (io_read (source, &ch, 1) == 1);
1071     }
1072     linenum[k] = NULL_CHAR;
1073     num = (int) strtol (linenum, NO_VAR, 10);
1074     ABEND (errno == ERANGE, "strange line number", NO_TEXT);
1075 /* COPY original line into buffer */
1076     ASSERT (io_read (source, &ch, 1) == 1);
1077     line = &buffer[n];
1078     while (ch != NEWLINE_CHAR) {
1079       buffer[n++] = ch;
1080       ASSERT (io_read (source, &ch, 1) == 1);
1081       ABEND ((unsigned) n >= len, "buffer overflow", NO_TEXT);
1082     }
1083     buffer[n++] = NEWLINE_CHAR;
1084     buffer[n] = NULL_CHAR;
1085     append_source_line (line, &ref_l, &num, fn);
1086   }
1087   return (A68_TRUE);
1088 }
1089 
1090 /**
1091 @brief Read source file and make internal copy.
1092 @return Whether reading is satisfactory .
1093 **/
1094 
1095 static BOOL_T
read_source_file(void)1096 read_source_file (void)
1097 {
1098   LINE_T *ref_l = NO_LINE;
1099   int line_num = 0, k, bytes_read;
1100   ssize_t l;
1101   FILE_T f = FILE_SOURCE_FD (&program);
1102   char **prelude_start, **postlude, *buffer;
1103 /* Prelude */
1104   if (OPTION_STROPPING (&program) == UPPER_STROPPING) {
1105     prelude_start = bold_prelude_start;
1106     postlude = bold_postlude;
1107   } else if (OPTION_STROPPING (&program) == QUOTE_STROPPING) {
1108     prelude_start = quote_prelude_start;
1109     postlude = quote_postlude;
1110   } else {
1111     prelude_start = postlude = NO_VAR;
1112   }
1113   append_environ (prelude_start, &ref_l, &line_num, "prelude");
1114 /* Read the file into a single buffer, so we save on system calls */
1115   line_num = 1;
1116   buffer = (char *) get_temp_heap_space ((unsigned) (8 + source_file_size));
1117   RESET_ERRNO;
1118   ASSERT (lseek (f, 0, SEEK_SET) >= 0);
1119   ABEND (errno != 0, "error while reading source file", NO_TEXT);
1120   RESET_ERRNO;
1121   bytes_read = (int) io_read (f, buffer, (size_t) source_file_size);
1122   ABEND (errno != 0 || bytes_read != source_file_size, "error while reading source file", NO_TEXT);
1123 /* Link all lines into the list */
1124   k = 0;
1125   while (k < source_file_size) {
1126     l = 0;
1127     scan_buf[0] = NULL_CHAR;
1128     while (k < source_file_size && buffer[k] != NEWLINE_CHAR) {
1129       if (k < source_file_size - 1 && buffer[k] == CR_CHAR && buffer[k + 1] == NEWLINE_CHAR) {
1130         k++;
1131       } else {
1132         scan_buf[l++] = buffer[k++];
1133         scan_buf[l] = NULL_CHAR;
1134       }
1135     }
1136     scan_buf[l++] = NEWLINE_CHAR;
1137     scan_buf[l] = NULL_CHAR;
1138     if (k < source_file_size) {
1139       k++;
1140     }
1141     append_source_line (scan_buf, &ref_l, &line_num, FILE_SOURCE_NAME (&program));
1142     SCAN_ERROR (l != (ssize_t) strlen (scan_buf), NO_LINE, NO_TEXT, ERROR_FILE_SOURCE_CTRL);
1143   }
1144 /* Postlude */
1145   append_environ (postlude, &ref_l, &line_num, "postlude");
1146 /* Concatenate lines */
1147   concatenate_lines (TOP_LINE (&program));
1148 /* Include files */
1149   include_files (TOP_LINE (&program));
1150   return (A68_TRUE);
1151 }
1152 
1153 /**
1154 @brief Next_char get next character from internal copy of source file.
1155 @param ref_l Source line we're scanning.
1156 @param ref_s Character (in source line) we're scanning.
1157 @param allow_typo Whether typographical display features are allowed.
1158 @return Next char on input.
1159 **/
1160 
1161 static char
next_char(LINE_T ** ref_l,char ** ref_s,BOOL_T allow_typo)1162 next_char (LINE_T ** ref_l, char **ref_s, BOOL_T allow_typo)
1163 {
1164   char ch;
1165 #if defined NO_TYPO
1166   allow_typo = A68_FALSE;
1167 #endif
1168   LOW_STACK_ALERT (NO_NODE);
1169 /* Source empty? */
1170   if (*ref_l == NO_LINE) {
1171     return (STOP_CHAR);
1172   } else {
1173     LIST (*ref_l) = (BOOL_T) (OPTION_NODEMASK (&program) & SOURCE_MASK ? A68_TRUE : A68_FALSE);
1174 /* Take new line? */
1175     if ((*ref_s)[0] == NEWLINE_CHAR || (*ref_s)[0] == NULL_CHAR) {
1176       *ref_l = NEXT (*ref_l);
1177       if (*ref_l == NO_LINE) {
1178         return (STOP_CHAR);
1179       }
1180       *ref_s = STRING (*ref_l);
1181     } else {
1182       (*ref_s)++;
1183     }
1184 /* Deliver next char */
1185     ch = (*ref_s)[0];
1186     if (allow_typo && (IS_SPACE (ch) || ch == FORMFEED_CHAR)) {
1187       ch = next_char (ref_l, ref_s, allow_typo);
1188     }
1189     return (ch);
1190   }
1191 }
1192 
1193 /**
1194 @brief Find first character that can start a valid symbol.
1195 @param ref_c Pointer to character.
1196 @param ref_l Source line we're scanning.
1197 @param ref_s Character (in source line) we're scanning.
1198 **/
1199 
1200 static void
get_good_char(char * ref_c,LINE_T ** ref_l,char ** ref_s)1201 get_good_char (char *ref_c, LINE_T ** ref_l, char **ref_s)
1202 {
1203   while (*ref_c != STOP_CHAR && (IS_SPACE (*ref_c) || (*ref_c == NULL_CHAR))) {
1204     if (*ref_l != NO_LINE) {
1205       LIST (*ref_l) = (BOOL_T) (OPTION_NODEMASK (&program) & SOURCE_MASK ? A68_TRUE : A68_FALSE);
1206     }
1207     *ref_c = next_char (ref_l, ref_s, A68_FALSE);
1208   }
1209 }
1210 
1211 /**
1212 @brief Handle a pragment (pragmat or comment).
1213 @param type Type of pragment (#, CO, COMMENT, PR, PRAGMAT).
1214 @param ref_l Source line we're scanning.
1215 @param ref_c Character (in source line) we're scanning.
1216 @return Pragment text as a string for binding in the tree.
1217 **/
1218 
1219 static char *
pragment(int type,LINE_T ** ref_l,char ** ref_c)1220 pragment (int type, LINE_T ** ref_l, char **ref_c)
1221 {
1222 #define INIT_BUFFER {chars_in_buf = 0; scan_buf[chars_in_buf] = NULL_CHAR;}
1223 #define ADD_ONE_CHAR(ch) {scan_buf[chars_in_buf ++] = ch; scan_buf[chars_in_buf] = NULL_CHAR;}
1224   char c = **ref_c, *term_s = NO_TEXT, *start_c = *ref_c;
1225   char *z;
1226   LINE_T *start_l = *ref_l;
1227   int term_s_length, chars_in_buf;
1228   BOOL_T stop, pragmat = A68_FALSE;
1229 /* Set terminator */
1230   if (OPTION_STROPPING (&program) == UPPER_STROPPING) {
1231     if (type == STYLE_I_COMMENT_SYMBOL) {
1232       term_s = "CO";
1233     } else if (type == STYLE_II_COMMENT_SYMBOL) {
1234       term_s = "#";
1235     } else if (type == BOLD_COMMENT_SYMBOL) {
1236       term_s = "COMMENT";
1237     } else if (type == STYLE_I_PRAGMAT_SYMBOL) {
1238       term_s = "PR";
1239       pragmat = A68_TRUE;
1240     } else if (type == BOLD_PRAGMAT_SYMBOL) {
1241       term_s = "PRAGMAT";
1242       pragmat = A68_TRUE;
1243     }
1244   } else if (OPTION_STROPPING (&program) == QUOTE_STROPPING) {
1245     if (type == STYLE_I_COMMENT_SYMBOL) {
1246       term_s = "'CO'";
1247     } else if (type == STYLE_II_COMMENT_SYMBOL) {
1248       term_s = "#";
1249     } else if (type == BOLD_COMMENT_SYMBOL) {
1250       term_s = "'COMMENT'";
1251     } else if (type == STYLE_I_PRAGMAT_SYMBOL) {
1252       term_s = "'PR'";
1253       pragmat = A68_TRUE;
1254     } else if (type == BOLD_PRAGMAT_SYMBOL) {
1255       term_s = "'PRAGMAT'";
1256       pragmat = A68_TRUE;
1257     }
1258   }
1259   term_s_length = (int) strlen (term_s);
1260 /* Scan for terminator */
1261   INIT_BUFFER;
1262   stop = A68_FALSE;
1263   while (stop == A68_FALSE) {
1264     SCAN_ERROR (c == STOP_CHAR, start_l, start_c, ERROR_UNTERMINATED_PRAGMENT);
1265 /* A ".." or '..' delimited string in a PRAGMAT */
1266     if (pragmat && (c == QUOTE_CHAR || (c == '\'' && OPTION_STROPPING (&program) == UPPER_STROPPING))) {
1267       char delim = c;
1268       BOOL_T eos = A68_FALSE;
1269       ADD_ONE_CHAR (c);
1270       c = next_char (ref_l, ref_c, A68_FALSE);
1271       while (!eos) {
1272         SCAN_ERROR (EOL (c), start_l, start_c, ERROR_LONG_STRING);
1273         if (c == delim) {
1274           ADD_ONE_CHAR (delim);
1275           save_state (*ref_l, *ref_c, c);
1276           c = next_char (ref_l, ref_c, A68_FALSE);
1277           if (c == delim) {
1278             c = next_char (ref_l, ref_c, A68_FALSE);
1279           } else {
1280             restore_state (ref_l, ref_c, &c);
1281             eos = A68_TRUE;
1282           }
1283         } else if (IS_PRINT (c)) {
1284           ADD_ONE_CHAR (c);
1285           c = next_char (ref_l, ref_c, A68_FALSE);
1286         } else {
1287           unworthy (start_l, start_c, c);
1288         }
1289       }
1290     } else if (EOL (c)) {
1291       ADD_ONE_CHAR (NEWLINE_CHAR);
1292     } else if (IS_PRINT (c) || IS_SPACE (c)) {
1293       ADD_ONE_CHAR (c);
1294     }
1295     if (chars_in_buf >= term_s_length) {
1296 /* Check whether we encountered the terminator */
1297       stop = (BOOL_T) (strcmp (term_s, &(scan_buf[chars_in_buf - term_s_length])) == 0);
1298     }
1299     c = next_char (ref_l, ref_c, A68_FALSE);
1300   }
1301   scan_buf[chars_in_buf - term_s_length] = NULL_CHAR;
1302   z = new_string (term_s, scan_buf, term_s, NO_TEXT);
1303   if (type == STYLE_I_PRAGMAT_SYMBOL || type == BOLD_PRAGMAT_SYMBOL) {
1304     isolate_options (scan_buf, start_l);
1305   }
1306   return (z);
1307 #undef ADD_ONE_CHAR
1308 #undef INIT_BUFFER
1309 }
1310 
1311 /**
1312 @brief Attribute for format item.
1313 @param ch Format item in character form.
1314 @return See brief description.
1315 **/
1316 
1317 static int
get_format_item(char ch)1318 get_format_item (char ch)
1319 {
1320   switch (TO_LOWER (ch)) {
1321   case 'a':{
1322       return (FORMAT_ITEM_A);
1323     }
1324   case 'b':{
1325       return (FORMAT_ITEM_B);
1326     }
1327   case 'c':{
1328       return (FORMAT_ITEM_C);
1329     }
1330   case 'd':{
1331       return (FORMAT_ITEM_D);
1332     }
1333   case 'e':{
1334       return (FORMAT_ITEM_E);
1335     }
1336   case 'f':{
1337       return (FORMAT_ITEM_F);
1338     }
1339   case 'g':{
1340       return (FORMAT_ITEM_G);
1341     }
1342   case 'h':{
1343       return (FORMAT_ITEM_H);
1344     }
1345   case 'i':{
1346       return (FORMAT_ITEM_I);
1347     }
1348   case 'j':{
1349       return (FORMAT_ITEM_J);
1350     }
1351   case 'k':{
1352       return (FORMAT_ITEM_K);
1353     }
1354   case 'l':
1355   case '/':{
1356       return (FORMAT_ITEM_L);
1357     }
1358   case 'm':{
1359       return (FORMAT_ITEM_M);
1360     }
1361   case 'n':{
1362       return (FORMAT_ITEM_N);
1363     }
1364   case 'o':{
1365       return (FORMAT_ITEM_O);
1366     }
1367   case 'p':{
1368       return (FORMAT_ITEM_P);
1369     }
1370   case 'q':{
1371       return (FORMAT_ITEM_Q);
1372     }
1373   case 'r':{
1374       return (FORMAT_ITEM_R);
1375     }
1376   case 's':{
1377       return (FORMAT_ITEM_S);
1378     }
1379   case 't':{
1380       return (FORMAT_ITEM_T);
1381     }
1382   case 'u':{
1383       return (FORMAT_ITEM_U);
1384     }
1385   case 'v':{
1386       return (FORMAT_ITEM_V);
1387     }
1388   case 'w':{
1389       return (FORMAT_ITEM_W);
1390     }
1391   case 'x':{
1392       return (FORMAT_ITEM_X);
1393     }
1394   case 'y':{
1395       return (FORMAT_ITEM_Y);
1396     }
1397   case 'z':{
1398       return (FORMAT_ITEM_Z);
1399     }
1400   case '+':{
1401       return (FORMAT_ITEM_PLUS);
1402     }
1403   case '-':{
1404       return (FORMAT_ITEM_MINUS);
1405     }
1406   case POINT_CHAR:{
1407       return (FORMAT_ITEM_POINT);
1408     }
1409   case '%':{
1410       return (FORMAT_ITEM_ESCAPE);
1411     }
1412   default:{
1413       return (0);
1414     }
1415   }
1416 }
1417 
1418 /* Macros */
1419 
1420 #define SCAN_DIGITS(c)\
1421   while (IS_DIGIT (c)) {\
1422     (sym++)[0] = (c);\
1423     (c) = next_char (ref_l, ref_s, A68_TRUE);\
1424   }
1425 
1426 #define SCAN_EXPONENT_PART(c)\
1427   (sym++)[0] = EXPONENT_CHAR;\
1428   (c) = next_char (ref_l, ref_s, A68_TRUE);\
1429   if ((c) == '+' || (c) == '-') {\
1430     (sym++)[0] = (c);\
1431     (c) = next_char (ref_l, ref_s, A68_TRUE);\
1432   }\
1433   SCAN_ERROR (!IS_DIGIT (c), *start_l, *start_c, ERROR_EXPONENT_DIGIT);\
1434   SCAN_DIGITS (c)
1435 
1436 /**
1437 @brief Whether input shows exponent character.
1438 @param ref_l Source line we're scanning.
1439 @param ref_s Character (in source line) we're scanning.
1440 @param ch Last scanned char.
1441 @return See brief description.
1442 **/
1443 
1444 static BOOL_T
is_exp_char(LINE_T ** ref_l,char ** ref_s,char * ch)1445 is_exp_char (LINE_T ** ref_l, char **ref_s, char *ch)
1446 {
1447   BOOL_T ret = A68_FALSE;
1448   char exp_syms[3];
1449   if (OPTION_STROPPING (&program) == UPPER_STROPPING) {
1450     exp_syms[0] = EXPONENT_CHAR;
1451     exp_syms[1] = (char) TO_UPPER (EXPONENT_CHAR);
1452     exp_syms[2] = NULL_CHAR;
1453   } else {
1454     exp_syms[0] = (char) TO_UPPER (EXPONENT_CHAR);
1455     exp_syms[1] = BACKSLASH_CHAR;
1456     exp_syms[2] = NULL_CHAR;
1457   }
1458   save_state (*ref_l, *ref_s, *ch);
1459   if (strchr (exp_syms, *ch) != NO_TEXT) {
1460     *ch = next_char (ref_l, ref_s, A68_TRUE);
1461     ret = (BOOL_T) (strchr ("+-0123456789", *ch) != NO_TEXT);
1462   }
1463   restore_state (ref_l, ref_s, ch);
1464   return (ret);
1465 }
1466 
1467 /**
1468 @brief Whether input shows radix character.
1469 @param ref_l Source line we're scanning.
1470 @param ref_s Character (in source line) we're scanning.
1471 @param ch Character to test.
1472 @return See brief description.
1473 **/
1474 
1475 static BOOL_T
is_radix_char(LINE_T ** ref_l,char ** ref_s,char * ch)1476 is_radix_char (LINE_T ** ref_l, char **ref_s, char *ch)
1477 {
1478   BOOL_T ret = A68_FALSE;
1479   save_state (*ref_l, *ref_s, *ch);
1480   if (OPTION_STROPPING (&program) == QUOTE_STROPPING) {
1481     if (*ch == TO_UPPER (RADIX_CHAR)) {
1482       *ch = next_char (ref_l, ref_s, A68_TRUE);
1483       ret = (BOOL_T) (strchr ("0123456789ABCDEF", *ch) != NO_TEXT);
1484     }
1485   } else {
1486     if (*ch == RADIX_CHAR) {
1487       *ch = next_char (ref_l, ref_s, A68_TRUE);
1488       ret = (BOOL_T) (strchr ("0123456789abcdef", *ch) != NO_TEXT);
1489     }
1490   }
1491   restore_state (ref_l, ref_s, ch);
1492   return (ret);
1493 }
1494 
1495 /**
1496 @brief Whether input shows decimal point.
1497 @param ref_l Source line we're scanning.
1498 @param ref_s Character (in source line) we're scanning.
1499 @param ch Character to test.
1500 @return See brief description.
1501 **/
1502 
1503 static BOOL_T
is_decimal_point(LINE_T ** ref_l,char ** ref_s,char * ch)1504 is_decimal_point (LINE_T ** ref_l, char **ref_s, char *ch)
1505 {
1506   BOOL_T ret = A68_FALSE;
1507   save_state (*ref_l, *ref_s, *ch);
1508   if (*ch == POINT_CHAR) {
1509     char exp_syms[3];
1510     if (OPTION_STROPPING (&program) == UPPER_STROPPING) {
1511       exp_syms[0] = EXPONENT_CHAR;
1512       exp_syms[1] = (char) TO_UPPER (EXPONENT_CHAR);
1513       exp_syms[2] = NULL_CHAR;
1514     } else {
1515       exp_syms[0] = (char) TO_UPPER (EXPONENT_CHAR);
1516       exp_syms[1] = BACKSLASH_CHAR;
1517       exp_syms[2] = NULL_CHAR;
1518     }
1519     *ch = next_char (ref_l, ref_s, A68_TRUE);
1520     if (strchr (exp_syms, *ch) != NO_TEXT) {
1521       *ch = next_char (ref_l, ref_s, A68_TRUE);
1522       ret = (BOOL_T) (strchr ("+-0123456789", *ch) != NO_TEXT);
1523     } else {
1524       ret = (BOOL_T) (strchr ("0123456789", *ch) != NO_TEXT);
1525     }
1526   }
1527   restore_state (ref_l, ref_s, ch);
1528   return (ret);
1529 }
1530 
1531 /**
1532 @brief Get next token from internal copy of source file..
1533 @param in_format Are we scanning a format text.
1534 @param ref_l Source line we're scanning.
1535 @param ref_s Character (in source line) we're scanning.
1536 @param start_l Line where token starts.
1537 @param start_c Character where token starts.
1538 @param att Attribute designated to token.
1539 **/
1540 
1541 static void
get_next_token(BOOL_T in_format,LINE_T ** ref_l,char ** ref_s,LINE_T ** start_l,char ** start_c,int * att)1542 get_next_token (BOOL_T in_format, LINE_T ** ref_l, char **ref_s, LINE_T ** start_l, char **start_c, int *att)
1543 {
1544   char c = **ref_s, *sym = scan_buf;
1545   sym[0] = NULL_CHAR;
1546   get_good_char (&c, ref_l, ref_s);
1547   *start_l = *ref_l;
1548   *start_c = *ref_s;
1549   if (c == STOP_CHAR) {
1550 /* We are at EOF */
1551     (sym++)[0] = STOP_CHAR;
1552     sym[0] = NULL_CHAR;
1553     return;
1554   }
1555 /***************/
1556 /* In a format */
1557 /***************/
1558   if (in_format) {
1559     char *format_items;
1560     if (OPTION_STROPPING (&program) == UPPER_STROPPING) {
1561       format_items = "/%\\+-.abcdefghijklmnopqrstuvwxyz";
1562     } else {                    /* if (OPTION_STROPPING (&program) == QUOTE_STROPPING) */
1563       format_items = "/%\\+-.ABCDEFGHIJKLMNOPQRSTUVWXYZ";
1564     }
1565     if (a68g_strchr (format_items, c) != NO_TEXT) {
1566 /* General format items */
1567       (sym++)[0] = c;
1568       sym[0] = NULL_CHAR;
1569       *att = get_format_item (c);
1570       (void) next_char (ref_l, ref_s, A68_FALSE);
1571       return;
1572     }
1573     if (IS_DIGIT (c)) {
1574 /* INT denotation for static replicator */
1575       SCAN_DIGITS (c);
1576       sym[0] = NULL_CHAR;
1577       *att = STATIC_REPLICATOR;
1578       return;
1579     }
1580   }
1581 /*******************/
1582 /* Not in a format */
1583 /*******************/
1584   if (IS_UPPER (c)) {
1585     if (OPTION_STROPPING (&program) == UPPER_STROPPING) {
1586 /* Upper case word - bold tag */
1587       while (IS_UPPER (c) || c == '_') {
1588         (sym++)[0] = c;
1589         c = next_char (ref_l, ref_s, A68_FALSE);
1590       }
1591       sym[0] = NULL_CHAR;
1592       *att = BOLD_TAG;
1593     } else if (OPTION_STROPPING (&program) == QUOTE_STROPPING) {
1594       while (IS_UPPER (c) || IS_DIGIT (c) || c == '_') {
1595         (sym++)[0] = c;
1596         c = next_char (ref_l, ref_s, A68_TRUE);
1597       }
1598       sym[0] = NULL_CHAR;
1599       *att = IDENTIFIER;
1600     }
1601   } else if (c == '\'') {
1602 /* Quote, uppercase word, quote - bold tag */
1603     int k = 0;
1604     c = next_char (ref_l, ref_s, A68_FALSE);
1605     while (IS_UPPER (c) || IS_DIGIT (c) || c == '_') {
1606       (sym++)[0] = c;
1607       k++;
1608       c = next_char (ref_l, ref_s, A68_TRUE);
1609     }
1610     SCAN_ERROR (k == 0, *start_l, *start_c, ERROR_QUOTED_BOLD_TAG);
1611     sym[0] = NULL_CHAR;
1612     *att = BOLD_TAG;
1613 /* Skip terminating quote, or complain if it is not there */
1614     SCAN_ERROR (c != '\'', *start_l, *start_c, ERROR_QUOTED_BOLD_TAG);
1615     c = next_char (ref_l, ref_s, A68_FALSE);
1616   } else if (IS_LOWER (c)) {
1617 /* Lower case word - identifier */
1618     while (IS_LOWER (c) || IS_DIGIT (c) || c == '_') {
1619       (sym++)[0] = c;
1620       c = next_char (ref_l, ref_s, A68_TRUE);
1621     }
1622     sym[0] = NULL_CHAR;
1623     *att = IDENTIFIER;
1624   } else if (c == POINT_CHAR) {
1625 /* Begins with a point symbol - point, dotdot, L REAL denotation */
1626     if (is_decimal_point (ref_l, ref_s, &c)) {
1627       (sym++)[0] = '0';
1628       (sym++)[0] = POINT_CHAR;
1629       c = next_char (ref_l, ref_s, A68_TRUE);
1630       SCAN_DIGITS (c);
1631       if (is_exp_char (ref_l, ref_s, &c)) {
1632         SCAN_EXPONENT_PART (c);
1633       }
1634       sym[0] = NULL_CHAR;
1635       *att = REAL_DENOTATION;
1636     } else {
1637       c = next_char (ref_l, ref_s, A68_TRUE);
1638       if (c == POINT_CHAR) {
1639         (sym++)[0] = POINT_CHAR;
1640         (sym++)[0] = POINT_CHAR;
1641         sym[0] = NULL_CHAR;
1642         *att = DOTDOT_SYMBOL;
1643         c = next_char (ref_l, ref_s, A68_FALSE);
1644       } else {
1645         (sym++)[0] = POINT_CHAR;
1646         sym[0] = NULL_CHAR;
1647         *att = POINT_SYMBOL;
1648       }
1649     }
1650   } else if (IS_DIGIT (c)) {
1651 /* Something that begins with a digit - L INT denotation, L REAL denotation */
1652     SCAN_DIGITS (c);
1653     if (is_decimal_point (ref_l, ref_s, &c)) {
1654       c = next_char (ref_l, ref_s, A68_TRUE);
1655       if (is_exp_char (ref_l, ref_s, &c)) {
1656         (sym++)[0] = POINT_CHAR;
1657         (sym++)[0] = '0';
1658         SCAN_EXPONENT_PART (c);
1659         *att = REAL_DENOTATION;
1660       } else {
1661         (sym++)[0] = POINT_CHAR;
1662         SCAN_DIGITS (c);
1663         if (is_exp_char (ref_l, ref_s, &c)) {
1664           SCAN_EXPONENT_PART (c);
1665         }
1666         *att = REAL_DENOTATION;
1667       }
1668     } else if (is_exp_char (ref_l, ref_s, &c)) {
1669       SCAN_EXPONENT_PART (c);
1670       *att = REAL_DENOTATION;
1671     } else if (is_radix_char (ref_l, ref_s, &c)) {
1672       (sym++)[0] = c;
1673       c = next_char (ref_l, ref_s, A68_TRUE);
1674       if (OPTION_STROPPING (&program) == UPPER_STROPPING) {
1675         while (IS_DIGIT (c) || strchr ("abcdef", c) != NO_TEXT) {
1676           (sym++)[0] = c;
1677           c = next_char (ref_l, ref_s, A68_TRUE);
1678         }
1679       } else {
1680         while (IS_DIGIT (c) || strchr ("ABCDEF", c) != NO_TEXT) {
1681           (sym++)[0] = c;
1682           c = next_char (ref_l, ref_s, A68_TRUE);
1683         }
1684       }
1685       *att = BITS_DENOTATION;
1686     } else {
1687       *att = INT_DENOTATION;
1688     }
1689     sym[0] = NULL_CHAR;
1690   } else if (c == QUOTE_CHAR) {
1691 /* STRING denotation */
1692     BOOL_T stop = A68_FALSE;
1693     while (!stop) {
1694       c = next_char (ref_l, ref_s, A68_FALSE);
1695       while (c != QUOTE_CHAR && c != STOP_CHAR) {
1696         SCAN_ERROR (EOL (c), *start_l, *start_c, ERROR_LONG_STRING);
1697         (sym++)[0] = c;
1698         c = next_char (ref_l, ref_s, A68_FALSE);
1699       }
1700       SCAN_ERROR (*ref_l == NO_LINE, *start_l, *start_c, ERROR_UNTERMINATED_STRING);
1701       c = next_char (ref_l, ref_s, A68_FALSE);
1702       if (c == QUOTE_CHAR) {
1703         (sym++)[0] = QUOTE_CHAR;
1704       } else {
1705         stop = A68_TRUE;
1706       }
1707     }
1708     sym[0] = NULL_CHAR;
1709     *att = (in_format ? LITERAL : ROW_CHAR_DENOTATION);
1710   } else if (a68g_strchr ("#$()[]{},;@", c) != NO_TEXT) {
1711 /* Single character symbols */
1712     (sym++)[0] = c;
1713     (void) next_char (ref_l, ref_s, A68_FALSE);
1714     sym[0] = NULL_CHAR;
1715     *att = 0;
1716   } else if (c == '|') {
1717 /* Bar */
1718     (sym++)[0] = c;
1719     c = next_char (ref_l, ref_s, A68_FALSE);
1720     if (c == ':') {
1721       (sym++)[0] = c;
1722       (void) next_char (ref_l, ref_s, A68_FALSE);
1723     }
1724     sym[0] = NULL_CHAR;
1725     *att = 0;
1726   } else if (c == '!' && OPTION_STROPPING (&program) == QUOTE_STROPPING) {
1727 /* Bar, will be replaced with modern variant.
1728    For this reason ! is not a MONAD with quote-stropping */
1729     (sym++)[0] = '|';
1730     c = next_char (ref_l, ref_s, A68_FALSE);
1731     if (c == ':') {
1732       (sym++)[0] = c;
1733       (void) next_char (ref_l, ref_s, A68_FALSE);
1734     }
1735     sym[0] = NULL_CHAR;
1736     *att = 0;
1737   } else if (c == ':') {
1738 /* Colon, semicolon, IS, ISNT */
1739     (sym++)[0] = c;
1740     c = next_char (ref_l, ref_s, A68_FALSE);
1741     if (c == '=') {
1742       (sym++)[0] = c;
1743       if ((c = next_char (ref_l, ref_s, A68_FALSE)) == ':') {
1744         (sym++)[0] = c;
1745         c = next_char (ref_l, ref_s, A68_FALSE);
1746       }
1747     } else if (c == '/') {
1748       (sym++)[0] = c;
1749       if ((c = next_char (ref_l, ref_s, A68_FALSE)) == '=') {
1750         (sym++)[0] = c;
1751         if ((c = next_char (ref_l, ref_s, A68_FALSE)) == ':') {
1752           (sym++)[0] = c;
1753           c = next_char (ref_l, ref_s, A68_FALSE);
1754         }
1755       }
1756     } else if (c == ':') {
1757       (sym++)[0] = c;
1758       if ((c = next_char (ref_l, ref_s, A68_FALSE)) == '=') {
1759         (sym++)[0] = c;
1760       }
1761     }
1762     sym[0] = NULL_CHAR;
1763     *att = 0;
1764   } else if (c == '=') {
1765 /* Operator starting with "=" */
1766     char *scanned = sym;
1767     (sym++)[0] = c;
1768     c = next_char (ref_l, ref_s, A68_FALSE);
1769     if (a68g_strchr (NOMADS, c) != NO_TEXT) {
1770       (sym++)[0] = c;
1771       c = next_char (ref_l, ref_s, A68_FALSE);
1772     }
1773     if (c == '=') {
1774       (sym++)[0] = c;
1775       if (next_char (ref_l, ref_s, A68_FALSE) == ':') {
1776         (sym++)[0] = ':';
1777         c = next_char (ref_l, ref_s, A68_FALSE);
1778         if (strlen (sym) < 4 && c == '=') {
1779           (sym++)[0] = '=';
1780           (void) next_char (ref_l, ref_s, A68_FALSE);
1781         }
1782       }
1783     } else if (c == ':') {
1784       (sym++)[0] = c;
1785       sym[0] = NULL_CHAR;
1786       if (next_char (ref_l, ref_s, A68_FALSE) == '=') {
1787         (sym++)[0] = '=';
1788         (void) next_char (ref_l, ref_s, A68_FALSE);
1789       } else {
1790         SCAN_ERROR (!(strcmp (scanned, "=:") == 0 || strcmp (scanned, "==:") == 0), *start_l, *start_c, ERROR_INVALID_OPERATOR_TAG);
1791       }
1792     }
1793     sym[0] = NULL_CHAR;
1794     if (strcmp (scanned, "=") == 0) {
1795       *att = EQUALS_SYMBOL;
1796     } else {
1797       *att = OPERATOR;
1798     }
1799   } else if (a68g_strchr (MONADS, c) != NO_TEXT || a68g_strchr (NOMADS, c) != NO_TEXT) {
1800 /* Operator */
1801     char *scanned = sym;
1802     (sym++)[0] = c;
1803     c = next_char (ref_l, ref_s, A68_FALSE);
1804     if (a68g_strchr (NOMADS, c) != NO_TEXT) {
1805       (sym++)[0] = c;
1806       c = next_char (ref_l, ref_s, A68_FALSE);
1807     }
1808     if (c == '=') {
1809       (sym++)[0] = c;
1810       if (next_char (ref_l, ref_s, A68_FALSE) == ':') {
1811         (sym++)[0] = ':';
1812         c = next_char (ref_l, ref_s, A68_FALSE);
1813         if (strlen (scanned) < 4 && c == '=') {
1814           (sym++)[0] = '=';
1815           (void) next_char (ref_l, ref_s, A68_FALSE);
1816         }
1817       }
1818     } else if (c == ':') {
1819       (sym++)[0] = c;
1820       sym[0] = NULL_CHAR;
1821       if (next_char (ref_l, ref_s, A68_FALSE) == '=') {
1822         (sym++)[0] = '=';
1823         sym[0] = NULL_CHAR;
1824         (void) next_char (ref_l, ref_s, A68_FALSE);
1825       } else {
1826         SCAN_ERROR (strcmp (&(scanned[1]), "=:") != 0, *start_l, *start_c, ERROR_INVALID_OPERATOR_TAG);
1827       }
1828     }
1829     sym[0] = NULL_CHAR;
1830     *att = OPERATOR;
1831   } else {
1832 /* Afuuus ... strange characters! */
1833     unworthy (*start_l, *start_c, (int) c);
1834   }
1835 }
1836 
1837 /**
1838 @brief Whether att opens an embedded clause.
1839 @param att Attribute under test.
1840 @return Whether att opens an embedded clause.
1841 **/
1842 
1843 static BOOL_T
open_nested_clause(int att)1844 open_nested_clause (int att)
1845 {
1846   switch (att) {
1847   case OPEN_SYMBOL:
1848   case BEGIN_SYMBOL:
1849   case PAR_SYMBOL:
1850   case IF_SYMBOL:
1851   case CASE_SYMBOL:
1852   case FOR_SYMBOL:
1853   case FROM_SYMBOL:
1854   case BY_SYMBOL:
1855   case TO_SYMBOL:
1856   case DOWNTO_SYMBOL:
1857   case WHILE_SYMBOL:
1858   case DO_SYMBOL:
1859   case SUB_SYMBOL:
1860   case ACCO_SYMBOL:
1861     {
1862       return (A68_TRUE);
1863     }
1864   }
1865   return (A68_FALSE);
1866 }
1867 
1868 /**
1869 @brief Whether att closes an embedded clause.
1870 @param att Attribute under test.
1871 @return Whether att closes an embedded clause.
1872 **/
1873 
1874 static BOOL_T
close_nested_clause(int att)1875 close_nested_clause (int att)
1876 {
1877   switch (att) {
1878   case CLOSE_SYMBOL:
1879   case END_SYMBOL:
1880   case FI_SYMBOL:
1881   case ESAC_SYMBOL:
1882   case OD_SYMBOL:
1883   case BUS_SYMBOL:
1884   case OCCA_SYMBOL:
1885     {
1886       return (A68_TRUE);
1887     }
1888   }
1889   return (A68_FALSE);
1890 }
1891 
1892 /**
1893 @brief Cast a string to lower case.
1894 @param p String to cast.
1895 **/
1896 
1897 static void
make_lower_case(char * p)1898 make_lower_case (char *p)
1899 {
1900   for (; p != NO_TEXT && p[0] != NULL_CHAR; p++) {
1901     p[0] = (char) TO_LOWER (p[0]);
1902   }
1903 }
1904 
1905 /**
1906 @brief Construct a linear list of tokens.
1907 @param root Node where to insert new symbol.
1908 @param level Current recursive descent depth.
1909 @param in_format Whether we scan a format.
1910 @param l Current source line.
1911 @param s Current character in source line.
1912 @param start_l Source line where symbol starts.
1913 @param start_c Character where symbol starts.
1914 **/
1915 
1916 static void
tokenise_source(NODE_T ** root,int level,BOOL_T in_format,LINE_T ** l,char ** s,LINE_T ** start_l,char ** start_c)1917 tokenise_source (NODE_T ** root, int level, BOOL_T in_format, LINE_T ** l, char **s, LINE_T ** start_l, char **start_c)
1918 {
1919   char *lpr = NO_TEXT;
1920   int lprt = 0;
1921   while (l != NO_VAR && !stop_scanner) {
1922     int att = 0;
1923     get_next_token (in_format, l, s, start_l, start_c, &att);
1924     if (scan_buf[0] == STOP_CHAR) {
1925       stop_scanner = A68_TRUE;
1926     } else if (strlen (scan_buf) > 0 || att == ROW_CHAR_DENOTATION || att == LITERAL) {
1927       KEYWORD_T *kw;
1928       char *c = NO_TEXT;
1929       BOOL_T make_node = A68_TRUE;
1930       char *trailing = NO_TEXT;
1931       if (att != IDENTIFIER) {
1932         kw = find_keyword (top_keyword, scan_buf);
1933       } else {
1934         kw = NO_KEYWORD;
1935       }
1936       if (!(kw != NO_KEYWORD && att != ROW_CHAR_DENOTATION)) {
1937         if (att == IDENTIFIER) {
1938           make_lower_case (scan_buf);
1939         }
1940         if (att != ROW_CHAR_DENOTATION && att != LITERAL) {
1941           int len = (int) strlen (scan_buf);
1942           while (len >= 1 && scan_buf[len - 1] == '_') {
1943             trailing = "_";
1944             scan_buf[len - 1] = NULL_CHAR;
1945             len--;
1946           }
1947         }
1948         c = TEXT (add_token (&top_token, scan_buf));
1949       } else {
1950         if (IS (kw, TO_SYMBOL)) {
1951 /* Merge GO and TO to GOTO */
1952           if (*root != NO_NODE && IS (*root, GO_SYMBOL)) {
1953             ATTRIBUTE (*root) = GOTO_SYMBOL;
1954             NSYMBOL (*root) = TEXT (find_keyword (top_keyword, "GOTO"));
1955             make_node = A68_FALSE;
1956           } else {
1957             att = ATTRIBUTE (kw);
1958             c = TEXT (kw);
1959           }
1960         } else {
1961           if (att == 0 || att == BOLD_TAG) {
1962             att = ATTRIBUTE (kw);
1963           }
1964           c = TEXT (kw);
1965 /* Handle pragments */
1966           if (att == STYLE_II_COMMENT_SYMBOL || att == STYLE_I_COMMENT_SYMBOL || att == BOLD_COMMENT_SYMBOL) {
1967             char *nlpr = pragment (ATTRIBUTE (kw), l, s);
1968             if (lpr == NO_TEXT || (int) strlen (lpr) == 0) {
1969               lpr = nlpr;
1970             } else {
1971               lpr = new_string (lpr, "\n\n", nlpr, NO_TEXT);
1972             }
1973             lprt = att;
1974             make_node = A68_FALSE;
1975           } else if (att == STYLE_I_PRAGMAT_SYMBOL || att == BOLD_PRAGMAT_SYMBOL) {
1976             char *nlpr = pragment (ATTRIBUTE (kw), l, s);
1977             if (lpr == NO_TEXT || (int) strlen (lpr) == 0) {
1978               lpr = nlpr;
1979             } else {
1980               lpr = new_string (lpr, "\n\n", nlpr, NO_TEXT);
1981             }
1982             lprt = att;
1983             if (!stop_scanner) {
1984               (void) set_options (OPTION_LIST (&program), A68_FALSE);
1985               make_node = A68_FALSE;
1986             }
1987           }
1988         }
1989       }
1990 /* Add token to the tree */
1991       if (make_node) {
1992         NODE_T *q = new_node ();
1993         INFO (q) = new_node_info ();
1994         switch (att) {
1995         case ASSIGN_SYMBOL:
1996         case END_SYMBOL:
1997         case ESAC_SYMBOL:
1998         case OD_SYMBOL:
1999         case OF_SYMBOL:
2000         case FI_SYMBOL:
2001         case CLOSE_SYMBOL:
2002         case BUS_SYMBOL:
2003         case COLON_SYMBOL:
2004         case COMMA_SYMBOL:
2005         case DOTDOT_SYMBOL:
2006         case SEMI_SYMBOL:
2007           {
2008             GINFO (q) = NO_GINFO;
2009             break;
2010           }
2011         default:{
2012             GINFO (q) = new_genie_info ();
2013             break;
2014           }
2015         }
2016         STATUS (q) = OPTION_NODEMASK (&program);
2017         LINE (INFO (q)) = *start_l;
2018         CHAR_IN_LINE (INFO (q)) = *start_c;
2019         PRIO (INFO (q)) = 0;
2020         PROCEDURE_LEVEL (INFO (q)) = 0;
2021         ATTRIBUTE (q) = att;
2022         NSYMBOL (q) = c;
2023         PREVIOUS (q) = *root;
2024         SUB (q) = NEXT (q) = NO_NODE;
2025         TABLE (q) = NO_TABLE;
2026         MOID (q) = NO_MOID;
2027         TAX (q) = NO_TAG;
2028         if (lpr != NO_TEXT) {
2029           NPRAGMENT (q) = lpr;
2030           NPRAGMENT_TYPE (q) = lprt;
2031           lpr = NO_TEXT;
2032           lprt = 0;
2033         }
2034         if (*root != NO_NODE) {
2035           NEXT (*root) = q;
2036         }
2037         if (TOP_NODE (&program) == NO_NODE) {
2038           TOP_NODE (&program) = q;
2039         }
2040         *root = q;
2041         if (trailing != NO_TEXT) {
2042           diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, q, WARNING_TRAILING, trailing, att);
2043         }
2044       }
2045 /*
2046 Redirection in tokenising formats. The scanner is a recursive-descent type as
2047 to know when it scans a format text and when not.
2048 */
2049       if (in_format && att == FORMAT_DELIMITER_SYMBOL) {
2050         return;
2051       } else if (!in_format && att == FORMAT_DELIMITER_SYMBOL) {
2052         tokenise_source (root, level + 1, A68_TRUE, l, s, start_l, start_c);
2053       } else if (in_format && open_nested_clause (att)) {
2054         NODE_T *z = PREVIOUS (*root);
2055         if (z != NO_NODE && is_one_of (z, FORMAT_ITEM_N, FORMAT_ITEM_G, FORMAT_ITEM_H, FORMAT_ITEM_F)) {
2056           tokenise_source (root, level, A68_FALSE, l, s, start_l, start_c);
2057         } else if (att == OPEN_SYMBOL) {
2058           ATTRIBUTE (*root) = FORMAT_OPEN_SYMBOL;
2059         } else if (OPTION_BRACKETS (&program) && att == SUB_SYMBOL) {
2060           ATTRIBUTE (*root) = FORMAT_OPEN_SYMBOL;
2061         } else if (OPTION_BRACKETS (&program) && att == ACCO_SYMBOL) {
2062           ATTRIBUTE (*root) = FORMAT_OPEN_SYMBOL;
2063         }
2064       } else if (!in_format && level > 0 && open_nested_clause (att)) {
2065         tokenise_source (root, level + 1, A68_FALSE, l, s, start_l, start_c);
2066       } else if (!in_format && level > 0 && close_nested_clause (att)) {
2067         return;
2068       } else if (in_format && att == CLOSE_SYMBOL) {
2069         ATTRIBUTE (*root) = FORMAT_CLOSE_SYMBOL;
2070       } else if (OPTION_BRACKETS (&program) && in_format && att == BUS_SYMBOL) {
2071         ATTRIBUTE (*root) = FORMAT_CLOSE_SYMBOL;
2072       } else if (OPTION_BRACKETS (&program) && in_format && att == OCCA_SYMBOL) {
2073         ATTRIBUTE (*root) = FORMAT_CLOSE_SYMBOL;
2074       }
2075     }
2076   }
2077 }
2078 
2079 /**
2080 @brief Tokenise source file, build initial syntax tree.
2081 @return Whether tokenising ended satisfactorily.
2082 **/
2083 
2084 BOOL_T
lexical_analyser(void)2085 lexical_analyser (void)
2086 {
2087   LINE_T *l, *start_l = NO_LINE;
2088   char *s = NO_TEXT, *start_c = NO_TEXT;
2089   NODE_T *root = NO_NODE;
2090   scan_buf = NO_TEXT;
2091   max_scan_buf_length = source_file_size = get_source_size ();
2092 /* Errors in file? */
2093   if (max_scan_buf_length == 0) {
2094     return (A68_FALSE);
2095   }
2096   if (OPTION_RUN_SCRIPT (&program)) {
2097     scan_buf = (char *) get_temp_heap_space ((unsigned) (8 + max_scan_buf_length));
2098     if (!read_script_file ()) {
2099       return (A68_FALSE);
2100     }
2101   } else {
2102     max_scan_buf_length += KILOBYTE;    /* for the environ, more than enough */
2103     scan_buf = (char *) get_temp_heap_space ((unsigned) max_scan_buf_length);
2104 /* Errors in file? */
2105     if (!read_source_file ()) {
2106       return (A68_FALSE);
2107     }
2108   }
2109 /* Start tokenising */
2110   read_error = A68_FALSE;
2111   stop_scanner = A68_FALSE;
2112   if ((l = TOP_LINE (&program)) != NO_LINE) {
2113     s = STRING (l);
2114   }
2115   tokenise_source (&root, 0, A68_FALSE, &l, &s, &start_l, &start_c);
2116   return (A68_TRUE);
2117 }
2118 
2119 /************************************************/
2120 /* A small refinement preprocessor for Algol68G */
2121 /************************************************/
2122 
2123 /**
2124 @brief Whether refinement terminator.
2125 @param p Position in syntax tree.
2126 @return See brief description.
2127 **/
2128 
2129 static BOOL_T
is_refinement_terminator(NODE_T * p)2130 is_refinement_terminator (NODE_T * p)
2131 {
2132   if (IS (p, POINT_SYMBOL)) {
2133     if (IN_PRELUDE (NEXT (p))) {
2134       return (A68_TRUE);
2135     } else {
2136       return (whether (p, POINT_SYMBOL, IDENTIFIER, COLON_SYMBOL, STOP));
2137     }
2138   } else {
2139     return (A68_FALSE);
2140   }
2141 }
2142 
2143 /**
2144 @brief Get refinement definitions in the internal source.
2145 **/
2146 
2147 void
get_refinements(void)2148 get_refinements (void)
2149 {
2150   NODE_T *p = TOP_NODE (&program);
2151   TOP_REFINEMENT (&program) = NO_REFINEMENT;
2152 /* First look where the prelude ends */
2153   while (p != NO_NODE && IN_PRELUDE (p)) {
2154     FORWARD (p);
2155   }
2156 /* Determine whether the program contains refinements at all */
2157   while (p != NO_NODE && !IN_PRELUDE (p) && !is_refinement_terminator (p)) {
2158     FORWARD (p);
2159   }
2160   if (p == NO_NODE || IN_PRELUDE (p)) {
2161     return;
2162   }
2163 /* Apparently this is code with refinements */
2164   FORWARD (p);
2165   if (p == NO_NODE || IN_PRELUDE (p)) {
2166 /* Ok, we accept a program with no refinements as well */
2167     return;
2168   }
2169   while (p != NO_NODE && !IN_PRELUDE (p) && whether (p, IDENTIFIER, COLON_SYMBOL, STOP)) {
2170     REFINEMENT_T *new_one = (REFINEMENT_T *) get_fixed_heap_space ((size_t) SIZE_AL (REFINEMENT_T)), *x;
2171     BOOL_T exists;
2172     NEXT (new_one) = NO_REFINEMENT;
2173     NAME (new_one) = NSYMBOL (p);
2174     APPLICATIONS (new_one) = 0;
2175     LINE_DEFINED (new_one) = LINE (INFO (p));
2176     LINE_APPLIED (new_one) = NO_LINE;
2177     NODE_DEFINED (new_one) = p;
2178     BEGIN (new_one) = END (new_one) = NO_NODE;
2179     p = NEXT_NEXT (p);
2180     if (p == NO_NODE) {
2181       diagnostic_node (A68_SYNTAX_ERROR, NO_NODE, ERROR_REFINEMENT_EMPTY);
2182       return;
2183     } else {
2184       BEGIN (new_one) = p;
2185     }
2186     while (p != NO_NODE && ATTRIBUTE (p) != POINT_SYMBOL) {
2187       END (new_one) = p;
2188       FORWARD (p);
2189     }
2190     if (p == NO_NODE) {
2191       diagnostic_node (A68_SYNTAX_ERROR, NO_NODE, ERROR_SYNTAX_EXPECTED, POINT_SYMBOL);
2192       return;
2193     } else {
2194       FORWARD (p);
2195     }
2196 /* Do we already have one by this name */
2197     x = TOP_REFINEMENT (&program);
2198     exists = A68_FALSE;
2199     while (x != NO_REFINEMENT && !exists) {
2200       if (NAME (x) == NAME (new_one)) {
2201         diagnostic_node (A68_SYNTAX_ERROR, NODE_DEFINED (new_one), ERROR_REFINEMENT_DEFINED);
2202         exists = A68_TRUE;
2203       }
2204       FORWARD (x);
2205     }
2206 /* Straight insertion in chain */
2207     if (!exists) {
2208       NEXT (new_one) = TOP_REFINEMENT (&program);
2209       TOP_REFINEMENT (&program) = new_one;
2210     }
2211   }
2212   if (p != NO_NODE && !IN_PRELUDE (p)) {
2213     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_REFINEMENT_INVALID);
2214   }
2215 }
2216 
2217 /**
2218 @brief Put refinement applications in the internal source.
2219 **/
2220 
2221 void
put_refinements(void)2222 put_refinements (void)
2223 {
2224   REFINEMENT_T *x;
2225   NODE_T *p, *point;
2226 /* If there are no refinements, there's little to do */
2227   if (TOP_REFINEMENT (&program) == NO_REFINEMENT) {
2228     return;
2229   }
2230 /* Initialisation */
2231   x = TOP_REFINEMENT (&program);
2232   while (x != NO_REFINEMENT) {
2233     APPLICATIONS (x) = 0;
2234     FORWARD (x);
2235   }
2236 /* Before we introduce infinite loops, find where closing-prelude starts */
2237   p = TOP_NODE (&program);
2238   while (p != NO_NODE && IN_PRELUDE (p)) {
2239     FORWARD (p);
2240   }
2241   while (p != NO_NODE && !IN_PRELUDE (p)) {
2242     FORWARD (p);
2243   }
2244   ABEND (p == NO_NODE, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
2245   point = p;
2246 /* We need to substitute until the first point */
2247   p = TOP_NODE (&program);
2248   while (p != NO_NODE && ATTRIBUTE (p) != POINT_SYMBOL) {
2249     if (IS (p, IDENTIFIER)) {
2250 /* See if we can find its definition */
2251       REFINEMENT_T *y = NO_REFINEMENT;
2252       x = TOP_REFINEMENT (&program);
2253       while (x != NO_REFINEMENT && y == NO_REFINEMENT) {
2254         if (NAME (x) == NSYMBOL (p)) {
2255           y = x;
2256         } else {
2257           FORWARD (x);
2258         }
2259       }
2260       if (y != NO_REFINEMENT) {
2261 /* We found its definition */
2262         APPLICATIONS (y)++;
2263         if (APPLICATIONS (y) > 1) {
2264           diagnostic_node (A68_SYNTAX_ERROR, NODE_DEFINED (y), ERROR_REFINEMENT_APPLIED);
2265           FORWARD (p);
2266         } else {
2267 /* Tie the definition in the tree */
2268           LINE_APPLIED (y) = LINE (INFO (p));
2269           if (PREVIOUS (p) != NO_NODE) {
2270             NEXT (PREVIOUS (p)) = BEGIN (y);
2271           }
2272           if (BEGIN (y) != NO_NODE) {
2273             PREVIOUS (BEGIN (y)) = PREVIOUS (p);
2274           }
2275           if (NEXT (p) != NO_NODE) {
2276             PREVIOUS (NEXT (p)) = END (y);
2277           }
2278           if (END (y) != NO_NODE) {
2279             NEXT (END (y)) = NEXT (p);
2280           }
2281           p = BEGIN (y);        /* So we can substitute the refinements within */
2282         }
2283       } else {
2284         FORWARD (p);
2285       }
2286     } else {
2287       FORWARD (p);
2288     }
2289   }
2290 /* After the point we ignore it all until the prelude */
2291   if (p != NO_NODE && IS (p, POINT_SYMBOL)) {
2292     if (PREVIOUS (p) != NO_NODE) {
2293       NEXT (PREVIOUS (p)) = point;
2294     }
2295     if (PREVIOUS (point) != NO_NODE) {
2296       PREVIOUS (point) = PREVIOUS (p);
2297     }
2298   } else {
2299     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_SYNTAX_EXPECTED, POINT_SYMBOL);
2300   }
2301 /* Has the programmer done it well? */
2302   if (ERROR_COUNT (&program) == 0) {
2303     x = TOP_REFINEMENT (&program);
2304     while (x != NO_REFINEMENT) {
2305       if (APPLICATIONS (x) == 0) {
2306         diagnostic_node (A68_SYNTAX_ERROR, NODE_DEFINED (x), ERROR_REFINEMENT_NOT_APPLIED);
2307       }
2308       FORWARD (x);
2309     }
2310   }
2311 }
2312 
2313 /*****************************************************/
2314 /* Top-down parser, elaborates the control structure */
2315 /*****************************************************/
2316 
2317 /**
2318 @brief Insert alt equals symbol.
2319 @param p Node after which to insert.
2320 **/
2321 
2322 static void
insert_alt_equals(NODE_T * p)2323 insert_alt_equals (NODE_T * p)
2324 {
2325   NODE_T *q = new_node ();
2326   *q = *p;
2327   INFO (q) = new_node_info ();
2328   *INFO (q) = *INFO (p);
2329   GINFO (q) = new_genie_info ();
2330   *GINFO (q) = *GINFO (p);
2331   ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
2332   NSYMBOL (q) = TEXT (add_token (&top_token, "="));
2333   NEXT (p) = q;
2334   PREVIOUS (q) = p;
2335   if (NEXT (q) != NO_NODE) {
2336     PREVIOUS (NEXT (q)) = q;
2337   }
2338 }
2339 
2340 /**
2341 @brief Substitute brackets.
2342 @param p Node in syntax tree.
2343 **/
2344 
2345 void
substitute_brackets(NODE_T * p)2346 substitute_brackets (NODE_T * p)
2347 {
2348   for (; p != NO_NODE; FORWARD (p)) {
2349     substitute_brackets (SUB (p));
2350     switch (ATTRIBUTE (p)) {
2351     case ACCO_SYMBOL:
2352       {
2353         ATTRIBUTE (p) = OPEN_SYMBOL;
2354         break;
2355       }
2356     case OCCA_SYMBOL:
2357       {
2358         ATTRIBUTE (p) = CLOSE_SYMBOL;
2359         break;
2360       }
2361     case SUB_SYMBOL:
2362       {
2363         ATTRIBUTE (p) = OPEN_SYMBOL;
2364         break;
2365       }
2366     case BUS_SYMBOL:
2367       {
2368         ATTRIBUTE (p) = CLOSE_SYMBOL;
2369         break;
2370       }
2371     }
2372   }
2373 }
2374 
2375 /**
2376 @brief Whether token terminates a unit.
2377 @param p Node in syntax tree.
2378 \return TRUE or FALSE whether token terminates a unit
2379 **/
2380 
2381 static BOOL_T
is_unit_terminator(NODE_T * p)2382 is_unit_terminator (NODE_T * p)
2383 {
2384   switch (ATTRIBUTE (p)) {
2385   case BUS_SYMBOL:
2386   case CLOSE_SYMBOL:
2387   case END_SYMBOL:
2388   case SEMI_SYMBOL:
2389   case EXIT_SYMBOL:
2390   case COMMA_SYMBOL:
2391   case THEN_BAR_SYMBOL:
2392   case ELSE_BAR_SYMBOL:
2393   case THEN_SYMBOL:
2394   case ELIF_SYMBOL:
2395   case ELSE_SYMBOL:
2396   case FI_SYMBOL:
2397   case IN_SYMBOL:
2398   case OUT_SYMBOL:
2399   case OUSE_SYMBOL:
2400   case ESAC_SYMBOL:
2401   case EDOC_SYMBOL:
2402   case OCCA_SYMBOL:
2403     {
2404       return (A68_TRUE);
2405     }
2406   }
2407   return (A68_FALSE);
2408 }
2409 
2410 /**
2411 @brief Whether token is a unit-terminator in a loop clause.
2412 @param p Node in syntax tree.
2413 @return Whether token is a unit-terminator in a loop clause.
2414 **/
2415 
2416 static BOOL_T
is_loop_keyword(NODE_T * p)2417 is_loop_keyword (NODE_T * p)
2418 {
2419   switch (ATTRIBUTE (p)) {
2420   case FOR_SYMBOL:
2421   case FROM_SYMBOL:
2422   case BY_SYMBOL:
2423   case TO_SYMBOL:
2424   case DOWNTO_SYMBOL:
2425   case WHILE_SYMBOL:
2426   case DO_SYMBOL:
2427     {
2428       return (A68_TRUE);
2429     }
2430   }
2431   return (A68_FALSE);
2432 }
2433 
2434 /**
2435 @brief Whether token cannot follow semicolon or EXIT.
2436 @param p Node in syntax tree.
2437 @return Whether token cannot follow semicolon or EXIT.
2438 **/
2439 
2440 static BOOL_T
is_semicolon_less(NODE_T * p)2441 is_semicolon_less (NODE_T * p)
2442 {
2443   switch (ATTRIBUTE (p)) {
2444   case BUS_SYMBOL:
2445   case CLOSE_SYMBOL:
2446   case END_SYMBOL:
2447   case SEMI_SYMBOL:
2448   case EXIT_SYMBOL:
2449   case THEN_BAR_SYMBOL:
2450   case ELSE_BAR_SYMBOL:
2451   case THEN_SYMBOL:
2452   case ELIF_SYMBOL:
2453   case ELSE_SYMBOL:
2454   case FI_SYMBOL:
2455   case IN_SYMBOL:
2456   case OUT_SYMBOL:
2457   case OUSE_SYMBOL:
2458   case ESAC_SYMBOL:
2459   case EDOC_SYMBOL:
2460   case OCCA_SYMBOL:
2461   case OD_SYMBOL:
2462   case UNTIL_SYMBOL:
2463     {
2464       return (A68_TRUE);
2465     }
2466   default:
2467     {
2468       return (A68_FALSE);
2469     }
2470   }
2471 }
2472 
2473 /**
2474 @brief Get good attribute.
2475 @param p Node in syntax tree.
2476 @return See brief description.
2477 **/
2478 
2479 static int
get_good_attribute(NODE_T * p)2480 get_good_attribute (NODE_T * p)
2481 {
2482   switch (ATTRIBUTE (p)) {
2483   case UNIT:
2484   case TERTIARY:
2485   case SECONDARY:
2486   case PRIMARY:
2487     {
2488       return (get_good_attribute (SUB (p)));
2489     }
2490   default:
2491     {
2492       return (ATTRIBUTE (p));
2493     }
2494   }
2495 }
2496 
2497 /**
2498 @brief Preferably don't put intelligible diagnostic here.
2499 @param p Node in syntax tree.
2500 @return See brief description.
2501 **/
2502 
2503 static BOOL_T
dont_mark_here(NODE_T * p)2504 dont_mark_here (NODE_T * p)
2505 {
2506   switch (ATTRIBUTE (p)) {
2507   case ACCO_SYMBOL:
2508   case ALT_DO_SYMBOL:
2509   case ALT_EQUALS_SYMBOL:
2510   case ANDF_SYMBOL:
2511   case ASSERT_SYMBOL:
2512   case ASSIGN_SYMBOL:
2513   case ASSIGN_TO_SYMBOL:
2514   case AT_SYMBOL:
2515   case BEGIN_SYMBOL:
2516   case BITS_SYMBOL:
2517   case BOLD_COMMENT_SYMBOL:
2518   case BOLD_PRAGMAT_SYMBOL:
2519   case BOOL_SYMBOL:
2520   case BUS_SYMBOL:
2521   case BY_SYMBOL:
2522   case BYTES_SYMBOL:
2523   case CASE_SYMBOL:
2524   case CHANNEL_SYMBOL:
2525   case CHAR_SYMBOL:
2526   case CLOSE_SYMBOL:
2527   case CODE_SYMBOL:
2528   case COLON_SYMBOL:
2529   case COLUMN_SYMBOL:
2530   case COMMA_SYMBOL:
2531   case COMPLEX_SYMBOL:
2532   case COMPL_SYMBOL:
2533   case DIAGONAL_SYMBOL:
2534   case DO_SYMBOL:
2535   case DOTDOT_SYMBOL:
2536   case DOWNTO_SYMBOL:
2537   case EDOC_SYMBOL:
2538   case ELIF_SYMBOL:
2539   case ELSE_BAR_SYMBOL:
2540   case ELSE_SYMBOL:
2541   case EMPTY_SYMBOL:
2542   case END_SYMBOL:
2543   case ENVIRON_SYMBOL:
2544   case EQUALS_SYMBOL:
2545   case ESAC_SYMBOL:
2546   case EXIT_SYMBOL:
2547   case FALSE_SYMBOL:
2548   case FILE_SYMBOL:
2549   case FI_SYMBOL:
2550   case FLEX_SYMBOL:
2551   case FORMAT_DELIMITER_SYMBOL:
2552   case FORMAT_SYMBOL:
2553   case FOR_SYMBOL:
2554   case FROM_SYMBOL:
2555   case GO_SYMBOL:
2556   case GOTO_SYMBOL:
2557   case HEAP_SYMBOL:
2558   case IF_SYMBOL:
2559   case IN_SYMBOL:
2560   case INT_SYMBOL:
2561   case ISNT_SYMBOL:
2562   case IS_SYMBOL:
2563   case LOC_SYMBOL:
2564   case LONG_SYMBOL:
2565   case MAIN_SYMBOL:
2566   case MODE_SYMBOL:
2567   case NIL_SYMBOL:
2568   case OCCA_SYMBOL:
2569   case OD_SYMBOL:
2570   case OF_SYMBOL:
2571   case OPEN_SYMBOL:
2572   case OP_SYMBOL:
2573   case ORF_SYMBOL:
2574   case OUSE_SYMBOL:
2575   case OUT_SYMBOL:
2576   case PAR_SYMBOL:
2577   case PIPE_SYMBOL:
2578   case POINT_SYMBOL:
2579   case PRIO_SYMBOL:
2580   case PROC_SYMBOL:
2581   case REAL_SYMBOL:
2582   case REF_SYMBOL:
2583   case ROWS_SYMBOL:
2584   case ROW_SYMBOL:
2585   case SEMA_SYMBOL:
2586   case SEMI_SYMBOL:
2587   case SHORT_SYMBOL:
2588   case SKIP_SYMBOL:
2589   case SOUND_SYMBOL:
2590   case STRING_SYMBOL:
2591   case STRUCT_SYMBOL:
2592   case STYLE_I_COMMENT_SYMBOL:
2593   case STYLE_II_COMMENT_SYMBOL:
2594   case STYLE_I_PRAGMAT_SYMBOL:
2595   case SUB_SYMBOL:
2596   case THEN_BAR_SYMBOL:
2597   case THEN_SYMBOL:
2598   case TO_SYMBOL:
2599   case TRANSPOSE_SYMBOL:
2600   case TRUE_SYMBOL:
2601   case UNION_SYMBOL:
2602   case UNTIL_SYMBOL:
2603   case VOID_SYMBOL:
2604   case WHILE_SYMBOL:
2605 /* and than */
2606   case SERIAL_CLAUSE:
2607   case ENQUIRY_CLAUSE:
2608   case INITIALISER_SERIES:
2609   case DECLARATION_LIST:
2610     {
2611       return (A68_TRUE);
2612     }
2613   }
2614   return (A68_FALSE);
2615 }
2616 
2617 /**
2618 @brief Intelligible diagnostic from syntax tree branch.
2619 @param p Node in syntax tree.
2620 @param w Where to put error message.
2621 @return See brief description.
2622 **/
2623 
2624 char *
phrase_to_text(NODE_T * p,NODE_T ** w)2625 phrase_to_text (NODE_T * p, NODE_T ** w)
2626 {
2627 #define MAX_TERMINALS 8
2628   int count = 0, line = -1;
2629   static char buffer[BUFFER_SIZE];
2630   for (buffer[0] = NULL_CHAR; p != NO_NODE && count < MAX_TERMINALS; FORWARD (p)) {
2631     if (LINE_NUMBER (p) > 0) {
2632       int gatt = get_good_attribute (p);
2633       char *z = non_terminal_string (input_line, gatt);
2634 /*
2635 Where to put the error message? Bob Uzgalis noted that actual content of a
2636 diagnostic is not as important as accurately indicating *were* the problem is!
2637 */
2638       if (w != NO_VAR) {
2639         if (count == 0 || (*w) == NO_NODE) {
2640           *w = p;
2641         } else if (dont_mark_here (*w)) {
2642           *w = p;
2643         }
2644       }
2645 /* Add initiation */
2646       if (count == 0) {
2647         if (w != NO_VAR) {
2648           bufcat (buffer, "construct beginning with", BUFFER_SIZE);
2649         }
2650       } else if (count == 1) {
2651         bufcat (buffer, " followed by", BUFFER_SIZE);
2652       } else if (count == 2) {
2653         bufcat (buffer, " and then", BUFFER_SIZE);
2654       } else if (count >= 3) {
2655         bufcat (buffer, ",", BUFFER_SIZE);
2656       }
2657 /* Attribute or symbol */
2658       if (z != NO_TEXT && SUB (p) != NO_NODE) {
2659         if (gatt == IDENTIFIER || gatt == OPERATOR || gatt == DENOTATION) {
2660           ASSERT (snprintf (edit_line, SNPRINTF_SIZE, " \"%s\"", NSYMBOL (p)) >= 0);
2661           bufcat (buffer, edit_line, BUFFER_SIZE);
2662         } else {
2663           if (strchr ("aeio", z[0]) != NO_TEXT) {
2664             bufcat (buffer, " an", BUFFER_SIZE);
2665           } else {
2666             bufcat (buffer, " a", BUFFER_SIZE);
2667           }
2668           ASSERT (snprintf (edit_line, SNPRINTF_SIZE, " %s", z) >= 0);
2669           bufcat (buffer, edit_line, BUFFER_SIZE);
2670         }
2671       } else if (z != NO_TEXT && SUB (p) == NO_NODE) {
2672         ASSERT (snprintf (edit_line, SNPRINTF_SIZE, " \"%s\"", NSYMBOL (p)) >= 0);
2673         bufcat (buffer, edit_line, BUFFER_SIZE);
2674       } else if (NSYMBOL (p) != NO_TEXT) {
2675         ASSERT (snprintf (edit_line, SNPRINTF_SIZE, " \"%s\"", NSYMBOL (p)) >= 0);
2676         bufcat (buffer, edit_line, BUFFER_SIZE);
2677       }
2678 /* Add "starting in line nn" */
2679       if (z != NO_TEXT && line != LINE_NUMBER (p)) {
2680         line = LINE_NUMBER (p);
2681         if (gatt == SERIAL_CLAUSE || gatt == ENQUIRY_CLAUSE || gatt == INITIALISER_SERIES) {
2682           bufcat (buffer, " starting", BUFFER_SIZE);
2683         }
2684         ASSERT (snprintf (edit_line, SNPRINTF_SIZE, " in line %d", line) >= 0);
2685         bufcat (buffer, edit_line, BUFFER_SIZE);
2686       }
2687       count++;
2688     }
2689   }
2690   if (p != NO_NODE && count == MAX_TERMINALS) {
2691     bufcat (buffer, " etcetera", BUFFER_SIZE);
2692   }
2693   return (buffer);
2694 }
2695 
2696 /**
2697 @brief Intelligible diagnostic from syntax tree branch.
2698 @param p Node in syntax tree.
2699 @param w Where to put error message.
2700 @return See brief description.
2701 **/
2702 
2703 char *
phrase_to_text_2(NODE_T * p,NODE_T ** w)2704 phrase_to_text_2 (NODE_T * p, NODE_T ** w)
2705 {
2706 #define MAX_TERMINALS 8
2707   int count = 0;
2708   static char buffer[BUFFER_SIZE];
2709   for (buffer[0] = NULL_CHAR; p != NO_NODE && count < MAX_TERMINALS; FORWARD (p)) {
2710     if (LINE_NUMBER (p) > 0) {
2711       char *z = non_terminal_string (input_line, ATTRIBUTE (p));
2712 /*
2713 Where to put the error message? Bob Uzgalis noted that actual content of a
2714 diagnostic is not as important as accurately indicating *were* the problem is!
2715 */
2716       if (w != NO_VAR) {
2717         if (count == 0 || (*w) == NO_NODE) {
2718           *w = p;
2719         } else if (dont_mark_here (*w)) {
2720           *w = p;
2721         }
2722       }
2723 /* Add initiation */
2724       if (count >= 1) {
2725         bufcat (buffer, ",", BUFFER_SIZE);
2726       }
2727 /* Attribute or symbol */
2728       if (z != NO_TEXT) {
2729         ASSERT (snprintf (edit_line, SNPRINTF_SIZE, " %s", z) >= 0);
2730         bufcat (buffer, edit_line, BUFFER_SIZE);
2731       } else if (NSYMBOL (p) != NO_TEXT) {
2732         ASSERT (snprintf (edit_line, SNPRINTF_SIZE, " \"%s\"", NSYMBOL (p)) >= 0);
2733         bufcat (buffer, edit_line, BUFFER_SIZE);
2734       }
2735       count++;
2736     }
2737   }
2738   if (p != NO_NODE && count == MAX_TERMINALS) {
2739     bufcat (buffer, " etcetera", BUFFER_SIZE);
2740   }
2741   return (buffer);
2742 }
2743 
2744 /*
2745 This is a parenthesis checker. After this checker, we know that at least
2746 brackets are matched. This stabilises later parser phases.
2747 Top-down parsing is done to place error diagnostics near offending lines.
2748 */
2749 
2750 static char bracket_check_error_text[BUFFER_SIZE];
2751 
2752 /**
2753 @brief Intelligible diagnostics for the bracket checker.
2754 @param txt Buffer to which to append text.
2755 @param n Count mismatch (~= 0).
2756 @param bra Opening bracket.
2757 @param ket Expected closing bracket.
2758 @return See brief description.
2759 **/
2760 
2761 static void
bracket_check_error(char * txt,int n,char * bra,char * ket)2762 bracket_check_error (char *txt, int n, char *bra, char *ket)
2763 {
2764   if (n != 0) {
2765     char b[BUFFER_SIZE];
2766     ASSERT (snprintf (b, SNPRINTF_SIZE, "\"%s\" without matching \"%s\"", (n > 0 ? bra : ket), (n > 0 ? ket : bra)) >= 0);
2767     if (strlen (txt) > 0) {
2768       bufcat (txt, " and ", BUFFER_SIZE);
2769     }
2770     bufcat (txt, b, BUFFER_SIZE);
2771   }
2772 }
2773 
2774 /**
2775 @brief Diagnose brackets in local branch of the tree.
2776 @param p Node in syntax tree.
2777 @return Error message.
2778 **/
2779 
2780 static char *
bracket_check_diagnose(NODE_T * p)2781 bracket_check_diagnose (NODE_T * p)
2782 {
2783   int begins = 0, opens = 0, format_delims = 0, format_opens = 0, subs = 0, ifs = 0, cases = 0, dos = 0, accos = 0;
2784   for (; p != NO_NODE; FORWARD (p)) {
2785     switch (ATTRIBUTE (p)) {
2786     case BEGIN_SYMBOL:
2787       {
2788         begins++;
2789         break;
2790       }
2791     case END_SYMBOL:
2792       {
2793         begins--;
2794         break;
2795       }
2796     case OPEN_SYMBOL:
2797       {
2798         opens++;
2799         break;
2800       }
2801     case CLOSE_SYMBOL:
2802       {
2803         opens--;
2804         break;
2805       }
2806     case ACCO_SYMBOL:
2807       {
2808         accos++;
2809         break;
2810       }
2811     case OCCA_SYMBOL:
2812       {
2813         accos--;
2814         break;
2815       }
2816     case FORMAT_DELIMITER_SYMBOL:
2817       {
2818         if (format_delims == 0) {
2819           format_delims = 1;
2820         } else {
2821           format_delims = 0;
2822         }
2823         break;
2824       }
2825     case FORMAT_OPEN_SYMBOL:
2826       {
2827         format_opens++;
2828         break;
2829       }
2830     case FORMAT_CLOSE_SYMBOL:
2831       {
2832         format_opens--;
2833         break;
2834       }
2835     case SUB_SYMBOL:
2836       {
2837         subs++;
2838         break;
2839       }
2840     case BUS_SYMBOL:
2841       {
2842         subs--;
2843         break;
2844       }
2845     case IF_SYMBOL:
2846       {
2847         ifs++;
2848         break;
2849       }
2850     case FI_SYMBOL:
2851       {
2852         ifs--;
2853         break;
2854       }
2855     case CASE_SYMBOL:
2856       {
2857         cases++;
2858         break;
2859       }
2860     case ESAC_SYMBOL:
2861       {
2862         cases--;
2863         break;
2864       }
2865     case DO_SYMBOL:
2866       {
2867         dos++;
2868         break;
2869       }
2870     case OD_SYMBOL:
2871       {
2872         dos--;
2873         break;
2874       }
2875     }
2876   }
2877   bracket_check_error_text[0] = NULL_CHAR;
2878   bracket_check_error (bracket_check_error_text, begins, "BEGIN", "END");
2879   bracket_check_error (bracket_check_error_text, opens, "(", ")");
2880   bracket_check_error (bracket_check_error_text, format_opens, "(", ")");
2881   bracket_check_error (bracket_check_error_text, format_delims, "$", "$");
2882   bracket_check_error (bracket_check_error_text, accos, "{", "}");
2883   bracket_check_error (bracket_check_error_text, subs, "[", "]");
2884   bracket_check_error (bracket_check_error_text, ifs, "IF", "FI");
2885   bracket_check_error (bracket_check_error_text, cases, "CASE", "ESAC");
2886   bracket_check_error (bracket_check_error_text, dos, "DO", "OD");
2887   return (bracket_check_error_text);
2888 }
2889 
2890 /**
2891 @brief Driver for locally diagnosing non-matching tokens.
2892 @param top
2893 @param p Node in syntax tree.
2894 @return Token from where to continue.
2895 **/
2896 
2897 static NODE_T *
bracket_check_parse(NODE_T * top,NODE_T * p)2898 bracket_check_parse (NODE_T * top, NODE_T * p)
2899 {
2900   BOOL_T ignore_token;
2901   for (; p != NO_NODE; FORWARD (p)) {
2902     int ket = STOP;
2903     NODE_T *q = NO_NODE;
2904     ignore_token = A68_FALSE;
2905     switch (ATTRIBUTE (p)) {
2906     case BEGIN_SYMBOL:
2907       {
2908         ket = END_SYMBOL;
2909         q = bracket_check_parse (top, NEXT (p));
2910         break;
2911       }
2912     case OPEN_SYMBOL:
2913       {
2914         ket = CLOSE_SYMBOL;
2915         q = bracket_check_parse (top, NEXT (p));
2916         break;
2917       }
2918     case ACCO_SYMBOL:
2919       {
2920         ket = OCCA_SYMBOL;
2921         q = bracket_check_parse (top, NEXT (p));
2922         break;
2923       }
2924     case FORMAT_OPEN_SYMBOL:
2925       {
2926         ket = FORMAT_CLOSE_SYMBOL;
2927         q = bracket_check_parse (top, NEXT (p));
2928         break;
2929       }
2930     case SUB_SYMBOL:
2931       {
2932         ket = BUS_SYMBOL;
2933         q = bracket_check_parse (top, NEXT (p));
2934         break;
2935       }
2936     case IF_SYMBOL:
2937       {
2938         ket = FI_SYMBOL;
2939         q = bracket_check_parse (top, NEXT (p));
2940         break;
2941       }
2942     case CASE_SYMBOL:
2943       {
2944         ket = ESAC_SYMBOL;
2945         q = bracket_check_parse (top, NEXT (p));
2946         break;
2947       }
2948     case DO_SYMBOL:
2949       {
2950         ket = OD_SYMBOL;
2951         q = bracket_check_parse (top, NEXT (p));
2952         break;
2953       }
2954     case END_SYMBOL:
2955     case OCCA_SYMBOL:
2956     case CLOSE_SYMBOL:
2957     case FORMAT_CLOSE_SYMBOL:
2958     case BUS_SYMBOL:
2959     case FI_SYMBOL:
2960     case ESAC_SYMBOL:
2961     case OD_SYMBOL:
2962       {
2963         return (p);
2964       }
2965     default:
2966       {
2967         ignore_token = A68_TRUE;
2968       }
2969     }
2970     if (ignore_token) {
2971       ;
2972     } else if (q != NO_NODE && IS (q, ket)) {
2973       p = q;
2974     } else if (q == NO_NODE) {
2975       char *diag = bracket_check_diagnose (top);
2976       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_PARENTHESIS, (strlen (diag) > 0 ? diag : INFO_MISSING_KEYWORDS));
2977       longjmp (top_down_crash_exit, 1);
2978     } else {
2979       char *diag = bracket_check_diagnose (top);
2980       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_PARENTHESIS_2, ATTRIBUTE (q), LINE (INFO (q)), ket, (strlen (diag) > 0 ? diag : INFO_MISSING_KEYWORDS));
2981       longjmp (top_down_crash_exit, 1);
2982     }
2983   }
2984   return (NO_NODE);
2985 }
2986 
2987 /**
2988 @brief Driver for globally diagnosing non-matching tokens.
2989 @param top Top node in syntax tree.
2990 **/
2991 
2992 void
check_parenthesis(NODE_T * top)2993 check_parenthesis (NODE_T * top)
2994 {
2995   if (!setjmp (top_down_crash_exit)) {
2996     if (bracket_check_parse (top, top) != NO_NODE) {
2997       diagnostic_node (A68_SYNTAX_ERROR, top, ERROR_PARENTHESIS, INFO_MISSING_KEYWORDS);
2998     }
2999   }
3000 }
3001 
3002 /*
3003 Next is a top-down parser that branches out the basic blocks.
3004 After this we can assign symbol tables to basic blocks.
3005 */
3006 
3007 /**
3008 @brief Give diagnose from top-down parser.
3009 @param start Embedding clause starts here.
3010 @param posit Error issued at this point.
3011 @param clause Type of clause being processed.
3012 @param expected Token expected.
3013 **/
3014 
3015 static void
top_down_diagnose(NODE_T * start,NODE_T * posit,int clause,int expected)3016 top_down_diagnose (NODE_T * start, NODE_T * posit, int clause, int expected)
3017 {
3018   NODE_T *issue = (posit != NO_NODE ? posit : start);
3019   if (expected != 0) {
3020     diagnostic_node (A68_SYNTAX_ERROR, issue, ERROR_EXPECTED_NEAR, expected, clause, NSYMBOL (start), LINE (INFO (start)));
3021   } else {
3022     diagnostic_node (A68_SYNTAX_ERROR, issue, ERROR_UNBALANCED_KEYWORD, clause, NSYMBOL (start), LINE (INFO (start)));
3023   }
3024 }
3025 
3026 /**
3027 @brief Check for premature exhaustion of tokens.
3028 @param p Node in syntax tree.
3029 @param q
3030 **/
3031 
3032 static void
tokens_exhausted(NODE_T * p,NODE_T * q)3033 tokens_exhausted (NODE_T * p, NODE_T * q)
3034 {
3035   if (p == NO_NODE) {
3036     diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_KEYWORD);
3037     longjmp (top_down_crash_exit, 1);
3038   }
3039 }
3040 
3041 /* This part specifically branches out loop clauses */
3042 
3043 /**
3044 @brief Whether in cast or formula with loop clause.
3045 @param p Node in syntax tree.
3046 @return Number of symbols to skip.
3047 **/
3048 
3049 static int
is_loop_cast_formula(NODE_T * p)3050 is_loop_cast_formula (NODE_T * p)
3051 {
3052 /* Accept declarers that can appear in such casts but not much more */
3053   if (IS (p, VOID_SYMBOL)) {
3054     return (1);
3055   } else if (IS (p, INT_SYMBOL)) {
3056     return (1);
3057   } else if (IS (p, REF_SYMBOL)) {
3058     return (1);
3059   } else if (is_one_of (p, OPERATOR, BOLD_TAG, STOP)) {
3060     return (1);
3061   } else if (whether (p, UNION_SYMBOL, OPEN_SYMBOL, STOP)) {
3062     return (2);
3063   } else if (is_one_of (p, OPEN_SYMBOL, SUB_SYMBOL, STOP)) {
3064     int k;
3065     for (k = 0; p != NO_NODE && (is_one_of (p, OPEN_SYMBOL, SUB_SYMBOL, STOP)); FORWARD (p), k++) {
3066       ;
3067     }
3068     return (p != NO_NODE && (whether (p, UNION_SYMBOL, OPEN_SYMBOL, STOP) ? k : 0));
3069   }
3070   return (0);
3071 }
3072 
3073 /**
3074 @brief Skip a unit in a loop clause (FROM u BY u TO u).
3075 @param p Node in syntax tree.
3076 @return Token from where to proceed or NO_NODE.
3077 **/
3078 
3079 static NODE_T *
top_down_skip_loop_unit(NODE_T * p)3080 top_down_skip_loop_unit (NODE_T * p)
3081 {
3082 /* Unit may start with, or consist of, a loop */
3083   if (is_loop_keyword (p)) {
3084     p = top_down_loop (p);
3085   }
3086 /* Skip rest of unit */
3087   while (p != NO_NODE) {
3088     int k = is_loop_cast_formula (p);
3089     if (k != 0) {
3090 /* operator-cast series .. */
3091       while (p != NO_NODE && k != 0) {
3092         while (k != 0) {
3093           FORWARD (p);
3094           k--;
3095         }
3096         k = is_loop_cast_formula (p);
3097       }
3098 /* ... may be followed by a loop clause */
3099       if (is_loop_keyword (p)) {
3100         p = top_down_loop (p);
3101       }
3102     } else if (is_loop_keyword (p) || IS (p, OD_SYMBOL)) {
3103 /* new loop or end-of-loop */
3104       return (p);
3105     } else if (IS (p, COLON_SYMBOL)) {
3106       FORWARD (p);
3107 /* skip routine header: loop clause */
3108       if (p != NO_NODE && is_loop_keyword (p)) {
3109         p = top_down_loop (p);
3110       }
3111     } else if (is_one_of (p, SEMI_SYMBOL, COMMA_SYMBOL, STOP) || IS (p, EXIT_SYMBOL)) {
3112 /* Statement separators */
3113       return (p);
3114     } else {
3115       FORWARD (p);
3116     }
3117   }
3118   return (NO_NODE);
3119 }
3120 
3121 /**
3122 @brief Skip a loop clause.
3123 @param p Node in syntax tree.
3124 @return Token from where to proceed or NO_NODE.
3125 **/
3126 
3127 static NODE_T *
top_down_skip_loop_series(NODE_T * p)3128 top_down_skip_loop_series (NODE_T * p)
3129 {
3130   BOOL_T siga;
3131   do {
3132     p = top_down_skip_loop_unit (p);
3133     siga = (BOOL_T) (p != NO_NODE && (is_one_of (p, SEMI_SYMBOL, EXIT_SYMBOL, COMMA_SYMBOL, COLON_SYMBOL, STOP)));
3134     if (siga) {
3135       FORWARD (p);
3136     }
3137   } while (!(p == NO_NODE || !siga));
3138   return (p);
3139 }
3140 
3141 /**
3142 @brief Make branch of loop parts.
3143 @param p Node in syntax tree.
3144 @return Token from where to proceed or NO_NODE.
3145 **/
3146 
3147 NODE_T *
top_down_loop(NODE_T * p)3148 top_down_loop (NODE_T * p)
3149 {
3150   NODE_T *start = p, *q = p, *save;
3151   if (IS (q, FOR_SYMBOL)) {
3152     tokens_exhausted (FORWARD (q), start);
3153     if (IS (q, IDENTIFIER)) {
3154       ATTRIBUTE (q) = DEFINING_IDENTIFIER;
3155     } else {
3156       top_down_diagnose (start, q, LOOP_CLAUSE, IDENTIFIER);
3157       longjmp (top_down_crash_exit, 1);
3158     }
3159     tokens_exhausted (FORWARD (q), start);
3160     if (is_one_of (q, FROM_SYMBOL, BY_SYMBOL, TO_SYMBOL, DOWNTO_SYMBOL, WHILE_SYMBOL, STOP)) {
3161       ;
3162     } else if (IS (q, DO_SYMBOL)) {
3163       ATTRIBUTE (q) = ALT_DO_SYMBOL;
3164     } else {
3165       top_down_diagnose (start, q, LOOP_CLAUSE, STOP);
3166       longjmp (top_down_crash_exit, 1);
3167     }
3168   }
3169   if (IS (q, FROM_SYMBOL)) {
3170     start = q;
3171     q = top_down_skip_loop_unit (NEXT (q));
3172     tokens_exhausted (q, start);
3173     if (is_one_of (q, BY_SYMBOL, TO_SYMBOL, DOWNTO_SYMBOL, WHILE_SYMBOL, STOP)) {
3174       ;
3175     } else if (IS (q, DO_SYMBOL)) {
3176       ATTRIBUTE (q) = ALT_DO_SYMBOL;
3177     } else {
3178       top_down_diagnose (start, q, LOOP_CLAUSE, STOP);
3179       longjmp (top_down_crash_exit, 1);
3180     }
3181     make_sub (start, PREVIOUS (q), FROM_SYMBOL);
3182   }
3183   if (IS (q, BY_SYMBOL)) {
3184     start = q;
3185     q = top_down_skip_loop_series (NEXT (q));
3186     tokens_exhausted (q, start);
3187     if (is_one_of (q, TO_SYMBOL, DOWNTO_SYMBOL, WHILE_SYMBOL, STOP)) {
3188       ;
3189     } else if (IS (q, DO_SYMBOL)) {
3190       ATTRIBUTE (q) = ALT_DO_SYMBOL;
3191     } else {
3192       top_down_diagnose (start, q, LOOP_CLAUSE, STOP);
3193       longjmp (top_down_crash_exit, 1);
3194     }
3195     make_sub (start, PREVIOUS (q), BY_SYMBOL);
3196   }
3197   if (is_one_of (q, TO_SYMBOL, DOWNTO_SYMBOL, STOP)) {
3198     start = q;
3199     q = top_down_skip_loop_series (NEXT (q));
3200     tokens_exhausted (q, start);
3201     if (IS (q, WHILE_SYMBOL)) {
3202       ;
3203     } else if (IS (q, DO_SYMBOL)) {
3204       ATTRIBUTE (q) = ALT_DO_SYMBOL;
3205     } else {
3206       top_down_diagnose (start, q, LOOP_CLAUSE, STOP);
3207       longjmp (top_down_crash_exit, 1);
3208     }
3209     make_sub (start, PREVIOUS (q), TO_SYMBOL);
3210   }
3211   if (IS (q, WHILE_SYMBOL)) {
3212     start = q;
3213     q = top_down_skip_loop_series (NEXT (q));
3214     tokens_exhausted (q, start);
3215     if (IS (q, DO_SYMBOL)) {
3216       ATTRIBUTE (q) = ALT_DO_SYMBOL;
3217     } else {
3218       top_down_diagnose (start, q, LOOP_CLAUSE, DO_SYMBOL);
3219       longjmp (top_down_crash_exit, 1);
3220     }
3221     make_sub (start, PREVIOUS (q), WHILE_SYMBOL);
3222   }
3223   if (is_one_of (q, DO_SYMBOL, ALT_DO_SYMBOL, STOP)) {
3224     int k = ATTRIBUTE (q);
3225     start = q;
3226     q = top_down_skip_loop_series (NEXT (q));
3227     tokens_exhausted (q, start);
3228     if (ISNT (q, OD_SYMBOL)) {
3229       top_down_diagnose (start, q, LOOP_CLAUSE, OD_SYMBOL);
3230       longjmp (top_down_crash_exit, 1);
3231     }
3232     make_sub (start, q, k);
3233   }
3234   save = NEXT (start);
3235   make_sub (p, start, LOOP_CLAUSE);
3236   return (save);
3237 }
3238 
3239 /**
3240 @brief Driver for making branches of loop parts.
3241 @param p Node in syntax tree.
3242 **/
3243 
3244 static void
top_down_loops(NODE_T * p)3245 top_down_loops (NODE_T * p)
3246 {
3247   NODE_T *q = p;
3248   for (; q != NO_NODE; FORWARD (q)) {
3249     if (SUB (q) != NO_NODE) {
3250       top_down_loops (SUB (q));
3251     }
3252   }
3253   q = p;
3254   while (q != NO_NODE) {
3255     if (is_loop_keyword (q) != STOP) {
3256       q = top_down_loop (q);
3257     } else {
3258       FORWARD (q);
3259     }
3260   }
3261 }
3262 
3263 /**
3264 @brief Driver for making branches of until parts.
3265 @param p Node in syntax tree.
3266 **/
3267 
3268 static void
top_down_untils(NODE_T * p)3269 top_down_untils (NODE_T * p)
3270 {
3271   NODE_T *q = p;
3272   for (; q != NO_NODE; FORWARD (q)) {
3273     if (SUB (q) != NO_NODE) {
3274       top_down_untils (SUB (q));
3275     }
3276   }
3277   q = p;
3278   while (q != NO_NODE) {
3279     if (IS (q, UNTIL_SYMBOL)) {
3280       NODE_T *u = q;
3281       while (NEXT (u) != NO_NODE) {
3282         FORWARD (u);
3283       }
3284       make_sub (q, PREVIOUS (u), UNTIL_SYMBOL);
3285       return;
3286     } else {
3287       FORWARD (q);
3288     }
3289   }
3290 }
3291 
3292 /* Branch anything except parts of a loop */
3293 
3294 /**
3295 @brief Skip serial/enquiry clause (unit series).
3296 @param p Node in syntax tree.
3297 @return Token from where to proceed or NO_NODE.
3298 **/
3299 
3300 static NODE_T *
top_down_series(NODE_T * p)3301 top_down_series (NODE_T * p)
3302 {
3303   BOOL_T siga = A68_TRUE;
3304   while (siga) {
3305     siga = A68_FALSE;
3306     p = top_down_skip_unit (p);
3307     if (p != NO_NODE) {
3308       if (is_one_of (p, SEMI_SYMBOL, EXIT_SYMBOL, COMMA_SYMBOL, STOP)) {
3309         siga = A68_TRUE;
3310         FORWARD (p);
3311       }
3312     }
3313   }
3314   return (p);
3315 }
3316 
3317 /**
3318 @brief Make branch of BEGIN .. END.
3319 @param begin_p
3320 @return Token from where to proceed or NO_NODE.
3321 **/
3322 
3323 static NODE_T *
top_down_begin(NODE_T * begin_p)3324 top_down_begin (NODE_T * begin_p)
3325 {
3326   NODE_T *end_p = top_down_series (NEXT (begin_p));
3327   if (end_p == NO_NODE || ISNT (end_p, END_SYMBOL)) {
3328     top_down_diagnose (begin_p, end_p, ENCLOSED_CLAUSE, END_SYMBOL);
3329     longjmp (top_down_crash_exit, 1);
3330     return (NO_NODE);
3331   } else {
3332     make_sub (begin_p, end_p, BEGIN_SYMBOL);
3333     return (NEXT (begin_p));
3334   }
3335 }
3336 
3337 /**
3338 @brief Make branch of CODE .. EDOC.
3339 @param code_p
3340 @return Token from where to proceed or NO_NODE.
3341 **/
3342 
3343 static NODE_T *
top_down_code(NODE_T * code_p)3344 top_down_code (NODE_T * code_p)
3345 {
3346   NODE_T *edoc_p = top_down_series (NEXT (code_p));
3347   if (edoc_p == NO_NODE || ISNT (edoc_p, EDOC_SYMBOL)) {
3348     diagnostic_node (A68_SYNTAX_ERROR, code_p, ERROR_KEYWORD);
3349     longjmp (top_down_crash_exit, 1);
3350     return (NO_NODE);
3351   } else {
3352     make_sub (code_p, edoc_p, CODE_SYMBOL);
3353     return (NEXT (code_p));
3354   }
3355 }
3356 
3357 /**
3358 @brief Make branch of ( .. ).
3359 @param open_p
3360 @return Token from where to proceed or NO_NODE.
3361 **/
3362 
3363 static NODE_T *
top_down_open(NODE_T * open_p)3364 top_down_open (NODE_T * open_p)
3365 {
3366   NODE_T *then_bar_p = top_down_series (NEXT (open_p)), *elif_bar_p;
3367   if (then_bar_p != NO_NODE && IS (then_bar_p, CLOSE_SYMBOL)) {
3368     make_sub (open_p, then_bar_p, OPEN_SYMBOL);
3369     return (NEXT (open_p));
3370   }
3371   if (then_bar_p == NO_NODE || ISNT (then_bar_p, THEN_BAR_SYMBOL)) {
3372     top_down_diagnose (open_p, then_bar_p, ENCLOSED_CLAUSE, STOP);
3373     longjmp (top_down_crash_exit, 1);
3374   }
3375   make_sub (open_p, PREVIOUS (then_bar_p), OPEN_SYMBOL);
3376   elif_bar_p = top_down_series (NEXT (then_bar_p));
3377   if (elif_bar_p != NO_NODE && IS (elif_bar_p, CLOSE_SYMBOL)) {
3378     make_sub (then_bar_p, PREVIOUS (elif_bar_p), THEN_BAR_SYMBOL);
3379     make_sub (open_p, elif_bar_p, OPEN_SYMBOL);
3380     return (NEXT (open_p));
3381   }
3382   if (elif_bar_p != NO_NODE && IS (elif_bar_p, THEN_BAR_SYMBOL)) {
3383     NODE_T *close_p = top_down_series (NEXT (elif_bar_p));
3384     if (close_p == NO_NODE || ISNT (close_p, CLOSE_SYMBOL)) {
3385       top_down_diagnose (open_p, elif_bar_p, ENCLOSED_CLAUSE, CLOSE_SYMBOL);
3386       longjmp (top_down_crash_exit, 1);
3387     }
3388     make_sub (then_bar_p, PREVIOUS (elif_bar_p), THEN_BAR_SYMBOL);
3389     make_sub (elif_bar_p, PREVIOUS (close_p), THEN_BAR_SYMBOL);
3390     make_sub (open_p, close_p, OPEN_SYMBOL);
3391     return (NEXT (open_p));
3392   }
3393   if (elif_bar_p != NO_NODE && IS (elif_bar_p, ELSE_BAR_SYMBOL)) {
3394     NODE_T *close_p = top_down_open (elif_bar_p);
3395     make_sub (then_bar_p, PREVIOUS (elif_bar_p), THEN_BAR_SYMBOL);
3396     make_sub (open_p, elif_bar_p, OPEN_SYMBOL);
3397     return (close_p);
3398   } else {
3399     top_down_diagnose (open_p, elif_bar_p, ENCLOSED_CLAUSE, CLOSE_SYMBOL);
3400     longjmp (top_down_crash_exit, 1);
3401     return (NO_NODE);
3402   }
3403 }
3404 
3405 /**
3406 @brief Make branch of [ .. ].
3407 @param sub_p
3408 @return Token from where to proceed or NO_NODE.
3409 **/
3410 
3411 static NODE_T *
top_down_sub(NODE_T * sub_p)3412 top_down_sub (NODE_T * sub_p)
3413 {
3414   NODE_T *bus_p = top_down_series (NEXT (sub_p));
3415   if (bus_p != NO_NODE && IS (bus_p, BUS_SYMBOL)) {
3416     make_sub (sub_p, bus_p, SUB_SYMBOL);
3417     return (NEXT (sub_p));
3418   } else {
3419     top_down_diagnose (sub_p, bus_p, 0, BUS_SYMBOL);
3420     longjmp (top_down_crash_exit, 1);
3421     return (NO_NODE);
3422   }
3423 }
3424 
3425 /**
3426 @brief Make branch of { .. }.
3427 @param acco_p
3428 @return Token from where to proceed or NO_NODE.
3429 **/
3430 
3431 static NODE_T *
top_down_acco(NODE_T * acco_p)3432 top_down_acco (NODE_T * acco_p)
3433 {
3434   NODE_T *occa_p = top_down_series (NEXT (acco_p));
3435   if (occa_p != NO_NODE && IS (occa_p, OCCA_SYMBOL)) {
3436     make_sub (acco_p, occa_p, ACCO_SYMBOL);
3437     return (NEXT (acco_p));
3438   } else {
3439     top_down_diagnose (acco_p, occa_p, ENCLOSED_CLAUSE, OCCA_SYMBOL);
3440     longjmp (top_down_crash_exit, 1);
3441     return (NO_NODE);
3442   }
3443 }
3444 
3445 /**
3446 @brief Make branch of IF .. THEN .. ELSE .. FI.
3447 @param if_p
3448 @return Token from where to proceed or NO_NODE.
3449 **/
3450 
3451 static NODE_T *
top_down_if(NODE_T * if_p)3452 top_down_if (NODE_T * if_p)
3453 {
3454   NODE_T *then_p = top_down_series (NEXT (if_p)), *elif_p;
3455   if (then_p == NO_NODE || ISNT (then_p, THEN_SYMBOL)) {
3456     top_down_diagnose (if_p, then_p, CONDITIONAL_CLAUSE, THEN_SYMBOL);
3457     longjmp (top_down_crash_exit, 1);
3458   }
3459   make_sub (if_p, PREVIOUS (then_p), IF_SYMBOL);
3460   elif_p = top_down_series (NEXT (then_p));
3461   if (elif_p != NO_NODE && IS (elif_p, FI_SYMBOL)) {
3462     make_sub (then_p, PREVIOUS (elif_p), THEN_SYMBOL);
3463     make_sub (if_p, elif_p, IF_SYMBOL);
3464     return (NEXT (if_p));
3465   }
3466   if (elif_p != NO_NODE && IS (elif_p, ELSE_SYMBOL)) {
3467     NODE_T *fi_p = top_down_series (NEXT (elif_p));
3468     if (fi_p == NO_NODE || ISNT (fi_p, FI_SYMBOL)) {
3469       top_down_diagnose (if_p, fi_p, CONDITIONAL_CLAUSE, FI_SYMBOL);
3470       longjmp (top_down_crash_exit, 1);
3471     } else {
3472       make_sub (then_p, PREVIOUS (elif_p), THEN_SYMBOL);
3473       make_sub (elif_p, PREVIOUS (fi_p), ELSE_SYMBOL);
3474       make_sub (if_p, fi_p, IF_SYMBOL);
3475       return (NEXT (if_p));
3476     }
3477   }
3478   if (elif_p != NO_NODE && IS (elif_p, ELIF_SYMBOL)) {
3479     NODE_T *fi_p = top_down_if (elif_p);
3480     make_sub (then_p, PREVIOUS (elif_p), THEN_SYMBOL);
3481     make_sub (if_p, elif_p, IF_SYMBOL);
3482     return (fi_p);
3483   } else {
3484     top_down_diagnose (if_p, elif_p, CONDITIONAL_CLAUSE, FI_SYMBOL);
3485     longjmp (top_down_crash_exit, 1);
3486     return (NO_NODE);
3487   }
3488 }
3489 
3490 /**
3491 @brief Make branch of CASE .. IN .. OUT .. ESAC.
3492 @param case_p
3493 @return Token from where to proceed or NO_NODE.
3494 **/
3495 
3496 static NODE_T *
top_down_case(NODE_T * case_p)3497 top_down_case (NODE_T * case_p)
3498 {
3499   NODE_T *in_p = top_down_series (NEXT (case_p)), *ouse_p;
3500   if (in_p == NO_NODE || ISNT (in_p, IN_SYMBOL)) {
3501     top_down_diagnose (case_p, in_p, ENCLOSED_CLAUSE, IN_SYMBOL);
3502     longjmp (top_down_crash_exit, 1);
3503   }
3504   make_sub (case_p, PREVIOUS (in_p), CASE_SYMBOL);
3505   ouse_p = top_down_series (NEXT (in_p));
3506   if (ouse_p != NO_NODE && IS (ouse_p, ESAC_SYMBOL)) {
3507     make_sub (in_p, PREVIOUS (ouse_p), IN_SYMBOL);
3508     make_sub (case_p, ouse_p, CASE_SYMBOL);
3509     return (NEXT (case_p));
3510   }
3511   if (ouse_p != NO_NODE && IS (ouse_p, OUT_SYMBOL)) {
3512     NODE_T *esac_p = top_down_series (NEXT (ouse_p));
3513     if (esac_p == NO_NODE || ISNT (esac_p, ESAC_SYMBOL)) {
3514       top_down_diagnose (case_p, esac_p, ENCLOSED_CLAUSE, ESAC_SYMBOL);
3515       longjmp (top_down_crash_exit, 1);
3516     } else {
3517       make_sub (in_p, PREVIOUS (ouse_p), IN_SYMBOL);
3518       make_sub (ouse_p, PREVIOUS (esac_p), OUT_SYMBOL);
3519       make_sub (case_p, esac_p, CASE_SYMBOL);
3520       return (NEXT (case_p));
3521     }
3522   }
3523   if (ouse_p != NO_NODE && IS (ouse_p, OUSE_SYMBOL)) {
3524     NODE_T *esac_p = top_down_case (ouse_p);
3525     make_sub (in_p, PREVIOUS (ouse_p), IN_SYMBOL);
3526     make_sub (case_p, ouse_p, CASE_SYMBOL);
3527     return (esac_p);
3528   } else {
3529     top_down_diagnose (case_p, ouse_p, ENCLOSED_CLAUSE, ESAC_SYMBOL);
3530     longjmp (top_down_crash_exit, 1);
3531     return (NO_NODE);
3532   }
3533 }
3534 
3535 /**
3536 @brief Skip a unit.
3537 @param p Node in syntax tree.
3538 @return Token from where to proceed or NO_NODE.
3539 **/
3540 
3541 NODE_T *
top_down_skip_unit(NODE_T * p)3542 top_down_skip_unit (NODE_T * p)
3543 {
3544   while (p != NO_NODE && !is_unit_terminator (p)) {
3545     if (IS (p, BEGIN_SYMBOL)) {
3546       p = top_down_begin (p);
3547     } else if (IS (p, SUB_SYMBOL)) {
3548       p = top_down_sub (p);
3549     } else if (IS (p, OPEN_SYMBOL)) {
3550       p = top_down_open (p);
3551     } else if (IS (p, IF_SYMBOL)) {
3552       p = top_down_if (p);
3553     } else if (IS (p, CASE_SYMBOL)) {
3554       p = top_down_case (p);
3555     } else if (IS (p, CODE_SYMBOL)) {
3556       p = top_down_code (p);
3557     } else if (IS (p, ACCO_SYMBOL)) {
3558       p = top_down_acco (p);
3559     } else {
3560       FORWARD (p);
3561     }
3562   }
3563   return (p);
3564 }
3565 
3566 static NODE_T *top_down_skip_format (NODE_T *);
3567 
3568 /**
3569 @brief Make branch of ( .. ) in a format.
3570 @param open_p
3571 @return Token from where to proceed or NO_NODE.
3572 **/
3573 
3574 static NODE_T *
top_down_format_open(NODE_T * open_p)3575 top_down_format_open (NODE_T * open_p)
3576 {
3577   NODE_T *close_p = top_down_skip_format (NEXT (open_p));
3578   if (close_p != NO_NODE && IS (close_p, FORMAT_CLOSE_SYMBOL)) {
3579     make_sub (open_p, close_p, FORMAT_OPEN_SYMBOL);
3580     return (NEXT (open_p));
3581   } else {
3582     top_down_diagnose (open_p, close_p, 0, FORMAT_CLOSE_SYMBOL);
3583     longjmp (top_down_crash_exit, 1);
3584     return (NO_NODE);
3585   }
3586 }
3587 
3588 /**
3589 @brief Skip a format text.
3590 @param p Node in syntax tree.
3591 @return Token from where to proceed or NO_NODE.
3592 **/
3593 
3594 static NODE_T *
top_down_skip_format(NODE_T * p)3595 top_down_skip_format (NODE_T * p)
3596 {
3597   while (p != NO_NODE) {
3598     if (IS (p, FORMAT_OPEN_SYMBOL)) {
3599       p = top_down_format_open (p);
3600     } else if (is_one_of (p, FORMAT_CLOSE_SYMBOL, FORMAT_DELIMITER_SYMBOL, STOP)) {
3601       return (p);
3602     } else {
3603       FORWARD (p);
3604     }
3605   }
3606   return (NO_NODE);
3607 }
3608 
3609 /**
3610 @brief Make branch of $ .. $.
3611 @param p Node in syntax tree.
3612 **/
3613 
3614 static void
top_down_formats(NODE_T * p)3615 top_down_formats (NODE_T * p)
3616 {
3617   NODE_T *q;
3618   for (q = p; q != NO_NODE; FORWARD (q)) {
3619     if (SUB (q) != NO_NODE) {
3620       top_down_formats (SUB (q));
3621     }
3622   }
3623   for (q = p; q != NO_NODE; FORWARD (q)) {
3624     if (IS (q, FORMAT_DELIMITER_SYMBOL)) {
3625       NODE_T *f = NEXT (q);
3626       while (f != NO_NODE && ISNT (f, FORMAT_DELIMITER_SYMBOL)) {
3627         if (IS (f, FORMAT_OPEN_SYMBOL)) {
3628           f = top_down_format_open (f);
3629         } else {
3630           f = NEXT (f);
3631         }
3632       }
3633       if (f == NO_NODE) {
3634         top_down_diagnose (p, f, FORMAT_TEXT, FORMAT_DELIMITER_SYMBOL);
3635         longjmp (top_down_crash_exit, 1);
3636       } else {
3637         make_sub (q, f, FORMAT_DELIMITER_SYMBOL);
3638       }
3639     }
3640   }
3641 }
3642 
3643 /**
3644 @brief Make branches of phrases for the bottom-up parser.
3645 @param p Node in syntax tree.
3646 **/
3647 
3648 void
top_down_parser(NODE_T * p)3649 top_down_parser (NODE_T * p)
3650 {
3651   if (p != NO_NODE) {
3652     if (!setjmp (top_down_crash_exit)) {
3653       (void) top_down_series (p);
3654       top_down_loops (p);
3655       top_down_untils (p);
3656       top_down_formats (p);
3657     }
3658   }
3659 }
3660 
3661 /********************************************/
3662 /* Bottom-up parser, reduces all constructs */
3663 /********************************************/
3664 
3665 /**
3666 @brief Detect redefined keyword.
3667 @param p Node in syntax tree.
3668 @param construct Where detected.
3669 */
3670 
3671 static void
detect_redefined_keyword(NODE_T * p,int construct)3672 detect_redefined_keyword (NODE_T * p, int construct)
3673 {
3674   if (p != NO_NODE && whether (p, KEYWORD, EQUALS_SYMBOL, STOP)) {
3675     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_REDEFINED_KEYWORD, NSYMBOL (p), construct);
3676   }
3677 }
3678 
3679 /**
3680 @brief Whether a series is serial or collateral.
3681 @param p Node in syntax tree.
3682 @return Whether a series is serial or collateral.
3683 **/
3684 
3685 static int
serial_or_collateral(NODE_T * p)3686 serial_or_collateral (NODE_T * p)
3687 {
3688   NODE_T *q;
3689   int semis = 0, commas = 0, exits = 0;
3690   for (q = p; q != NO_NODE; FORWARD (q)) {
3691     if (IS (q, COMMA_SYMBOL)) {
3692       commas++;
3693     } else if (IS (q, SEMI_SYMBOL)) {
3694       semis++;
3695     } else if (IS (q, EXIT_SYMBOL)) {
3696       exits++;
3697     }
3698   }
3699   if (semis == 0 && exits == 0 && commas > 0) {
3700     return (COLLATERAL_CLAUSE);
3701   } else if ((semis > 0 || exits > 0) && commas == 0) {
3702     return (SERIAL_CLAUSE);
3703   } else if (semis == 0 && exits == 0 && commas == 0) {
3704     return (SERIAL_CLAUSE);
3705   } else {
3706 /* Heuristic guess to give intelligible error message */
3707     return ((semis + exits) >= (commas ? SERIAL_CLAUSE : COLLATERAL_CLAUSE));
3708   }
3709 }
3710 
3711 /**
3712 @brief Whether formal bounds.
3713 @param p Node in syntax tree.
3714 @return Whether formal bounds.
3715 **/
3716 
3717 static BOOL_T
is_formal_bounds(NODE_T * p)3718 is_formal_bounds (NODE_T * p)
3719 {
3720   if (p == NO_NODE) {
3721     return (A68_TRUE);
3722   } else {
3723     switch (ATTRIBUTE (p)) {
3724     case OPEN_SYMBOL:
3725     case CLOSE_SYMBOL:
3726     case SUB_SYMBOL:
3727     case BUS_SYMBOL:
3728     case COMMA_SYMBOL:
3729     case COLON_SYMBOL:
3730     case DOTDOT_SYMBOL:
3731     case INT_DENOTATION:
3732     case IDENTIFIER:
3733     case OPERATOR:
3734       {
3735         return ((BOOL_T) (is_formal_bounds (SUB (p)) && is_formal_bounds (NEXT (p))));
3736       }
3737     default:
3738       {
3739         return (A68_FALSE);
3740       }
3741     }
3742   }
3743 }
3744 
3745 /**
3746 @brief Insert a node with attribute "a" after "p".
3747 @param p Node in syntax tree.
3748 @param a Attribute.
3749 **/
3750 
3751 static void
pad_node(NODE_T * p,int a)3752 pad_node (NODE_T * p, int a)
3753 {
3754 /*
3755 This is used to fill information that Algol 68 does not require to be present.
3756 Filling in gives one format for such construct; this helps later passes.
3757 */
3758   NODE_T *z = new_node ();
3759   *z = *p;
3760   if (GINFO (p) != NO_GINFO) {
3761     GINFO (z) = new_genie_info ();
3762   }
3763   PREVIOUS (z) = p;
3764   SUB (z) = NO_NODE;
3765   ATTRIBUTE (z) = a;
3766   MOID (z) = NO_MOID;
3767   if (NEXT (z) != NO_NODE) {
3768     PREVIOUS (NEXT (z)) = z;
3769   }
3770   NEXT (p) = z;
3771 }
3772 
3773 /**
3774 @brief Diagnose extensions.
3775 @param p Node in syntax tree.
3776 **/
3777 
3778 static void
a68_extension(NODE_T * p)3779 a68_extension (NODE_T * p)
3780 {
3781   if (OPTION_PORTCHECK (&program)) {
3782     diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, p, WARNING_EXTENSION);
3783   } else {
3784     diagnostic_node (A68_WARNING, p, WARNING_EXTENSION);
3785   }
3786 }
3787 
3788 /**
3789 @brief Diagnose for clauses not yielding a value.
3790 @param p Node in syntax tree.
3791 **/
3792 
3793 static void
empty_clause(NODE_T * p)3794 empty_clause (NODE_T * p)
3795 {
3796   diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_CLAUSE_WITHOUT_VALUE);
3797 }
3798 
3799 #if ! defined HAVE_PARALLEL_CLAUSE
3800 
3801 /**
3802 @brief Diagnose for parallel clause.
3803 @param p Node in syntax tree.
3804 **/
3805 
3806 static void
par_clause(NODE_T * p)3807 par_clause (NODE_T * p)
3808 {
3809   diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_NO_PARALLEL_CLAUSE);
3810 }
3811 
3812 #endif
3813 
3814 /**
3815 @brief Diagnose for missing symbol.
3816 @param p Node in syntax tree.
3817 **/
3818 
3819 static void
strange_tokens(NODE_T * p)3820 strange_tokens (NODE_T * p)
3821 {
3822   NODE_T *q = ((p != NO_NODE && NEXT (p) != NO_NODE) ? NEXT (p) : p);
3823   diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_STRANGE_TOKENS);
3824 }
3825 
3826 /**
3827 @brief Diagnose for strange separator.
3828 @param p Node in syntax tree.
3829 **/
3830 
3831 static void
strange_separator(NODE_T * p)3832 strange_separator (NODE_T * p)
3833 {
3834   NODE_T *q = ((p != NO_NODE && NEXT (p) != NO_NODE) ? NEXT (p) : p);
3835   diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_STRANGE_SEPARATOR);
3836 }
3837 
3838 /*
3839 Here is a set of routines that gather definitions from phrases.
3840 This way we can apply tags before defining them.
3841 These routines do not look very elegant as they have to scan through all
3842 kind of symbols to find a pattern that they recognise.
3843 */
3844 
3845 /**
3846 @brief Skip anything until a comma, semicolon or EXIT is found.
3847 @param p Node in syntax tree.
3848 @return Node from where to proceed.
3849 **/
3850 
3851 static NODE_T *
skip_unit(NODE_T * p)3852 skip_unit (NODE_T * p)
3853 {
3854   for (; p != NO_NODE; FORWARD (p)) {
3855     if (IS (p, COMMA_SYMBOL)) {
3856       return (p);
3857     } else if (IS (p, SEMI_SYMBOL)) {
3858       return (p);
3859     } else if (IS (p, EXIT_SYMBOL)) {
3860       return (p);
3861     }
3862   }
3863   return (NO_NODE);
3864 }
3865 
3866 /**
3867 @brief Attribute of entry in symbol table.
3868 @param table Current symbol table.
3869 @param name Token name.
3870 @return Attribute of entry in symbol table, or 0 if not found.
3871 **/
3872 
3873 static int
find_tag_definition(TABLE_T * table,char * name)3874 find_tag_definition (TABLE_T * table, char *name)
3875 {
3876   if (table != NO_TABLE) {
3877     int ret = 0;
3878     TAG_T *s;
3879     BOOL_T found;
3880     found = A68_FALSE;
3881     for (s = INDICANTS (table); s != NO_TAG && !found; FORWARD (s)) {
3882       if (NSYMBOL (NODE (s)) == name) {
3883         ret += INDICANT;
3884         found = A68_TRUE;
3885       }
3886     }
3887     found = A68_FALSE;
3888     for (s = OPERATORS (table); s != NO_TAG && !found; FORWARD (s)) {
3889       if (NSYMBOL (NODE (s)) == name) {
3890         ret += OPERATOR;
3891         found = A68_TRUE;
3892       }
3893     }
3894     if (ret == 0) {
3895       return (find_tag_definition (PREVIOUS (table), name));
3896     } else {
3897       return (ret);
3898     }
3899   } else {
3900     return (0);
3901   }
3902 }
3903 
3904 /**
3905 @brief Fill in whether bold tag is operator or indicant.
3906 @param p Node in syntax tree.
3907 **/
3908 
3909 static void
elaborate_bold_tags(NODE_T * p)3910 elaborate_bold_tags (NODE_T * p)
3911 {
3912   NODE_T *q;
3913   for (q = p; q != NO_NODE; FORWARD (q)) {
3914     if (IS (q, BOLD_TAG)) {
3915       switch (find_tag_definition (TABLE (q), NSYMBOL (q))) {
3916       case 0:
3917         {
3918           diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_UNDECLARED_TAG);
3919           break;
3920         }
3921       case INDICANT:
3922         {
3923           ATTRIBUTE (q) = INDICANT;
3924           break;
3925         }
3926       case OPERATOR:
3927         {
3928           ATTRIBUTE (q) = OPERATOR;
3929           break;
3930         }
3931       }
3932     }
3933   }
3934 }
3935 
3936 /**
3937 @brief Skip declarer, or argument pack and declarer.
3938 @param p Node in syntax tree.
3939 @return Node before token that is not part of pack or declarer .
3940 **/
3941 
3942 static NODE_T *
skip_pack_declarer(NODE_T * p)3943 skip_pack_declarer (NODE_T * p)
3944 {
3945 /* Skip () REF [] REF FLEX [] [] .. */
3946   while (p != NO_NODE && (is_one_of (p, SUB_SYMBOL, OPEN_SYMBOL, REF_SYMBOL, FLEX_SYMBOL, SHORT_SYMBOL, LONG_SYMBOL, STOP))) {
3947     FORWARD (p);
3948   }
3949 /* Skip STRUCT (), UNION () or PROC [()] */
3950   if (p != NO_NODE && (is_one_of (p, STRUCT_SYMBOL, UNION_SYMBOL, STOP))) {
3951     return (NEXT (p));
3952   } else if (p != NO_NODE && IS (p, PROC_SYMBOL)) {
3953     return (skip_pack_declarer (NEXT (p)));
3954   } else {
3955     return (p);
3956   }
3957 }
3958 
3959 /**
3960 @brief Search MODE A = .., B = .. and store indicants.
3961 @param p Node in syntax tree.
3962 **/
3963 
3964 static void
extract_indicants(NODE_T * p)3965 extract_indicants (NODE_T * p)
3966 {
3967   NODE_T *q = p;
3968   while (q != NO_NODE) {
3969     if (IS (q, MODE_SYMBOL)) {
3970       BOOL_T siga = A68_TRUE;
3971       do {
3972         FORWARD (q);
3973         detect_redefined_keyword (q, MODE_DECLARATION);
3974         if (whether (q, BOLD_TAG, EQUALS_SYMBOL, STOP)) {
3975 /* Store in the symbol table, but also in the moid list.
3976    Position of definition (q) connects to this lexical level!
3977 */
3978           ASSERT (add_tag (TABLE (p), INDICANT, q, NO_MOID, STOP) != NO_TAG);
3979           ASSERT (add_mode (&TOP_MOID (&program), INDICANT, 0, q, NO_MOID, NO_PACK) != NO_MOID);
3980           ATTRIBUTE (q) = DEFINING_INDICANT;
3981           FORWARD (q);
3982           ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
3983           q = skip_pack_declarer (NEXT (q));
3984           FORWARD (q);
3985         } else {
3986           siga = A68_FALSE;
3987         }
3988       } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
3989     } else {
3990       FORWARD (q);
3991     }
3992   }
3993 }
3994 
3995 #define GET_PRIORITY(q, k)\
3996   RESET_ERRNO;\
3997   (k) = atoi (NSYMBOL (q));\
3998   if (errno != 0) {\
3999     diagnostic_node (A68_SYNTAX_ERROR, (q), ERROR_INVALID_PRIORITY);\
4000     (k) = MAX_PRIORITY;\
4001   } else if ((k) < 1 || (k) > MAX_PRIORITY) {\
4002     diagnostic_node (A68_SYNTAX_ERROR, (q), ERROR_INVALID_PRIORITY);\
4003     (k) = MAX_PRIORITY;\
4004   }
4005 
4006 /**
4007 @brief Search PRIO X = .., Y = .. and store priorities.
4008 @param p Node in syntax tree.
4009 **/
4010 
4011 static void
extract_priorities(NODE_T * p)4012 extract_priorities (NODE_T * p)
4013 {
4014   NODE_T *q = p;
4015   while (q != NO_NODE) {
4016     if (IS (q, PRIO_SYMBOL)) {
4017       BOOL_T siga = A68_TRUE;
4018       do {
4019         FORWARD (q);
4020         detect_redefined_keyword (q, PRIORITY_DECLARATION);
4021 /* An operator tag like ++ or && gives strange errors so we catch it here */
4022         if (whether (q, OPERATOR, OPERATOR, STOP)) {
4023           int k;
4024           NODE_T *y = q;
4025           diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_INVALID_OPERATOR_TAG);
4026           ATTRIBUTE (q) = DEFINING_OPERATOR;
4027 /* Remove one superfluous operator, and hope it was only one.   	 */
4028           NEXT (q) = NEXT_NEXT (q);
4029           PREVIOUS (NEXT (q)) = q;
4030           FORWARD (q);
4031           ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
4032           FORWARD (q);
4033           GET_PRIORITY (q, k);
4034           ATTRIBUTE (q) = PRIORITY;
4035           ASSERT (add_tag (TABLE (p), PRIO_SYMBOL, y, NO_MOID, k) != NO_TAG);
4036           FORWARD (q);
4037         } else if (whether (q, OPERATOR, EQUALS_SYMBOL, INT_DENOTATION, STOP) || whether (q, EQUALS_SYMBOL, EQUALS_SYMBOL, INT_DENOTATION, STOP)) {
4038           int k;
4039           NODE_T *y = q;
4040           ATTRIBUTE (q) = DEFINING_OPERATOR;
4041           FORWARD (q);
4042           ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
4043           FORWARD (q);
4044           GET_PRIORITY (q, k);
4045           ATTRIBUTE (q) = PRIORITY;
4046           ASSERT (add_tag (TABLE (p), PRIO_SYMBOL, y, NO_MOID, k) != NO_TAG);
4047           FORWARD (q);
4048         } else if (whether (q, BOLD_TAG, IDENTIFIER, STOP)) {
4049           siga = A68_FALSE;
4050         } else if (whether (q, BOLD_TAG, EQUALS_SYMBOL, INT_DENOTATION, STOP)) {
4051           int k;
4052           NODE_T *y = q;
4053           ATTRIBUTE (q) = DEFINING_OPERATOR;
4054           FORWARD (q);
4055           ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
4056           FORWARD (q);
4057           GET_PRIORITY (q, k);
4058           ATTRIBUTE (q) = PRIORITY;
4059           ASSERT (add_tag (TABLE (p), PRIO_SYMBOL, y, NO_MOID, k) != NO_TAG);
4060           FORWARD (q);
4061         } else if (whether (q, BOLD_TAG, INT_DENOTATION, STOP) || whether (q, OPERATOR, INT_DENOTATION, STOP) || whether (q, EQUALS_SYMBOL, INT_DENOTATION, STOP)) {
4062 /* The scanner cannot separate operator and "=" sign so we do this here */
4063           int len = (int) strlen (NSYMBOL (q));
4064           if (len > 1 && NSYMBOL (q)[len - 1] == '=') {
4065             int k;
4066             NODE_T *y = q;
4067             char *sym = (char *) get_temp_heap_space ((size_t) (len + 1));
4068             bufcpy (sym, NSYMBOL (q), len + 1);
4069             sym[len - 1] = NULL_CHAR;
4070             NSYMBOL (q) = TEXT (add_token (&top_token, sym));
4071             if (len > 2 && NSYMBOL (q)[len - 2] == ':' && NSYMBOL (q)[len - 3] != '=') {
4072               diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_OPERATOR_INVALID_END);
4073             }
4074             ATTRIBUTE (q) = DEFINING_OPERATOR;
4075             insert_alt_equals (q);
4076             q = NEXT_NEXT (q);
4077             GET_PRIORITY (q, k);
4078             ATTRIBUTE (q) = PRIORITY;
4079             ASSERT (add_tag (TABLE (p), PRIO_SYMBOL, y, NO_MOID, k) != NO_TAG);
4080             FORWARD (q);
4081           } else {
4082             siga = A68_FALSE;
4083           }
4084         } else {
4085           siga = A68_FALSE;
4086         }
4087       } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
4088     } else {
4089       FORWARD (q);
4090     }
4091   }
4092 }
4093 
4094 /**
4095 @brief Search OP [( .. ) ..] X = .., Y = .. and store operators.
4096 @param p Node in syntax tree.
4097 **/
4098 
4099 static void
extract_operators(NODE_T * p)4100 extract_operators (NODE_T * p)
4101 {
4102   NODE_T *q = p;
4103   while (q != NO_NODE) {
4104     if (ISNT (q, OP_SYMBOL)) {
4105       FORWARD (q);
4106     } else {
4107       BOOL_T siga = A68_TRUE;
4108 /* Skip operator plan */
4109       if (NEXT (q) != NO_NODE && IS (NEXT (q), OPEN_SYMBOL)) {
4110         q = skip_pack_declarer (NEXT (q));
4111       }
4112 /* Sample operators */
4113       if (q != NO_NODE) {
4114         do {
4115           FORWARD (q);
4116           detect_redefined_keyword (q, OPERATOR_DECLARATION);
4117 /* Unacceptable operator tags like ++ or && could give strange errors */
4118           if (whether (q, OPERATOR, OPERATOR, STOP)) {
4119             diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_INVALID_OPERATOR_TAG);
4120             ATTRIBUTE (q) = DEFINING_OPERATOR;
4121             ASSERT (add_tag (TABLE (p), OP_SYMBOL, q, NO_MOID, STOP) != NO_TAG);
4122             NEXT (q) = NEXT_NEXT (q);   /* Remove one superfluous operator, and hope it was only one */
4123             PREVIOUS (NEXT (q)) = q;
4124             FORWARD (q);
4125             ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
4126             q = skip_unit (q);
4127           } else if (whether (q, OPERATOR, EQUALS_SYMBOL, STOP) || whether (q, EQUALS_SYMBOL, EQUALS_SYMBOL, STOP)) {
4128             ATTRIBUTE (q) = DEFINING_OPERATOR;
4129             ASSERT (add_tag (TABLE (p), OP_SYMBOL, q, NO_MOID, STOP) != NO_TAG);
4130             FORWARD (q);
4131             ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
4132             q = skip_unit (q);
4133           } else if (whether (q, BOLD_TAG, IDENTIFIER, STOP)) {
4134             siga = A68_FALSE;
4135           } else if (whether (q, BOLD_TAG, EQUALS_SYMBOL, STOP)) {
4136             ATTRIBUTE (q) = DEFINING_OPERATOR;
4137             ASSERT (add_tag (TABLE (p), OP_SYMBOL, q, NO_MOID, STOP) != NO_TAG);
4138             FORWARD (q);
4139             ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
4140             q = skip_unit (q);
4141           } else if (q != NO_NODE && (is_one_of (q, OPERATOR, BOLD_TAG, EQUALS_SYMBOL, STOP))) {
4142 /* The scanner cannot separate operator and "=" sign so we do this here */
4143             int len = (int) strlen (NSYMBOL (q));
4144             if (len > 1 && NSYMBOL (q)[len - 1] == '=') {
4145               char *sym = (char *) get_temp_heap_space ((size_t) (len + 1));
4146               bufcpy (sym, NSYMBOL (q), len + 1);
4147               sym[len - 1] = NULL_CHAR;
4148               NSYMBOL (q) = TEXT (add_token (&top_token, sym));
4149               if (len > 2 && NSYMBOL (q)[len - 2] == ':' && NSYMBOL (q)[len - 3] != '=') {
4150                 diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_OPERATOR_INVALID_END);
4151               }
4152               ATTRIBUTE (q) = DEFINING_OPERATOR;
4153               insert_alt_equals (q);
4154               ASSERT (add_tag (TABLE (p), OP_SYMBOL, q, NO_MOID, STOP) != NO_TAG);
4155               FORWARD (q);
4156               q = skip_unit (q);
4157             } else {
4158               siga = A68_FALSE;
4159             }
4160           } else {
4161             siga = A68_FALSE;
4162           }
4163         } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
4164       }
4165     }
4166   }
4167 }
4168 
4169 /**
4170 @brief Search and store labels.
4171 @param p Node in syntax tree.
4172 @param expect Information the parser may have on what is expected.
4173 **/
4174 
4175 static void
extract_labels(NODE_T * p,int expect)4176 extract_labels (NODE_T * p, int expect)
4177 {
4178   NODE_T *q;
4179 /* Only handle candidate phrases as not to search indexers! */
4180   if (expect == SERIAL_CLAUSE || expect == ENQUIRY_CLAUSE || expect == SOME_CLAUSE) {
4181     for (q = p; q != NO_NODE; FORWARD (q)) {
4182       if (whether (q, IDENTIFIER, COLON_SYMBOL, STOP)) {
4183         TAG_T *z = add_tag (TABLE (p), LABEL, q, NO_MOID, LOCAL_LABEL);
4184         ATTRIBUTE (q) = DEFINING_IDENTIFIER;
4185         UNIT (z) = NO_NODE;
4186       }
4187     }
4188   }
4189 }
4190 
4191 /**
4192 @brief Search MOID x = .., y = .. and store identifiers.
4193 @param p Node in syntax tree.
4194 **/
4195 
4196 static void
extract_identities(NODE_T * p)4197 extract_identities (NODE_T * p)
4198 {
4199   NODE_T *q = p;
4200   while (q != NO_NODE) {
4201     if (whether (q, DECLARER, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
4202       BOOL_T siga = A68_TRUE;
4203       do {
4204         if (whether ((FORWARD (q)), IDENTIFIER, EQUALS_SYMBOL, STOP)) {
4205           ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
4206           ATTRIBUTE (q) = DEFINING_IDENTIFIER;
4207           FORWARD (q);
4208           ATTRIBUTE (q) = ALT_EQUALS_SYMBOL;
4209           q = skip_unit (q);
4210         } else if (whether (q, IDENTIFIER, ASSIGN_SYMBOL, STOP)) {
4211 /* Handle common error in ALGOL 68 programs */
4212           diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_MIXED_DECLARATION);
4213           ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
4214           ATTRIBUTE (q) = DEFINING_IDENTIFIER;
4215           ATTRIBUTE (FORWARD (q)) = ALT_EQUALS_SYMBOL;
4216           q = skip_unit (q);
4217         } else {
4218           siga = A68_FALSE;
4219         }
4220       } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
4221     } else {
4222       FORWARD (q);
4223     }
4224   }
4225 }
4226 
4227 /**
4228 @brief Search MOID x [:= ..], y [:= ..] and store identifiers.
4229 @param p Node in syntax tree.
4230 **/
4231 
4232 static void
extract_variables(NODE_T * p)4233 extract_variables (NODE_T * p)
4234 {
4235   NODE_T *q = p;
4236   while (q != NO_NODE) {
4237     if (whether (q, DECLARER, IDENTIFIER, STOP)) {
4238       BOOL_T siga = A68_TRUE;
4239       do {
4240         FORWARD (q);
4241         if (whether (q, IDENTIFIER, STOP)) {
4242           if (whether (q, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
4243 /* Handle common error in ALGOL 68 programs */
4244             diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_MIXED_DECLARATION);
4245             ATTRIBUTE (NEXT (q)) = ASSIGN_SYMBOL;
4246           }
4247           ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
4248           ATTRIBUTE (q) = DEFINING_IDENTIFIER;
4249           q = skip_unit (q);
4250         } else {
4251           siga = A68_FALSE;
4252         }
4253       } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
4254     } else {
4255       FORWARD (q);
4256     }
4257   }
4258 }
4259 
4260 /**
4261 @brief Search PROC x = .., y = .. and stores identifiers.
4262 @param p Node in syntax tree.
4263 **/
4264 
4265 static void
extract_proc_identities(NODE_T * p)4266 extract_proc_identities (NODE_T * p)
4267 {
4268   NODE_T *q = p;
4269   while (q != NO_NODE) {
4270     if (whether (q, PROC_SYMBOL, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
4271       BOOL_T siga = A68_TRUE;
4272       do {
4273         FORWARD (q);
4274         if (whether (q, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
4275           TAG_T *t = add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER);
4276           IN_PROC (t) = A68_TRUE;
4277           ATTRIBUTE (q) = DEFINING_IDENTIFIER;
4278           ATTRIBUTE (FORWARD (q)) = ALT_EQUALS_SYMBOL;
4279           q = skip_unit (q);
4280         } else if (whether (q, IDENTIFIER, ASSIGN_SYMBOL, STOP)) {
4281 /* Handle common error in ALGOL 68 programs */
4282           diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_MIXED_DECLARATION);
4283           ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
4284           ATTRIBUTE (q) = DEFINING_IDENTIFIER;
4285           ATTRIBUTE (FORWARD (q)) = ALT_EQUALS_SYMBOL;
4286           q = skip_unit (q);
4287         } else {
4288           siga = A68_FALSE;
4289         }
4290       } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
4291     } else {
4292       FORWARD (q);
4293     }
4294   }
4295 }
4296 
4297 /**
4298 @brief Search PROC x [:= ..], y [:= ..]; store identifiers.
4299 @param p Node in syntax tree.
4300 **/
4301 
4302 static void
extract_proc_variables(NODE_T * p)4303 extract_proc_variables (NODE_T * p)
4304 {
4305   NODE_T *q = p;
4306   while (q != NO_NODE) {
4307     if (whether (q, PROC_SYMBOL, IDENTIFIER, STOP)) {
4308       BOOL_T siga = A68_TRUE;
4309       do {
4310         FORWARD (q);
4311         if (whether (q, IDENTIFIER, ASSIGN_SYMBOL, STOP)) {
4312           ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
4313           ATTRIBUTE (q) = DEFINING_IDENTIFIER;
4314           q = skip_unit (FORWARD (q));
4315         } else if (whether (q, IDENTIFIER, EQUALS_SYMBOL, STOP)) {
4316 /* Handle common error in ALGOL 68 programs */
4317           diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_SYNTAX_MIXED_DECLARATION);
4318           ASSERT (add_tag (TABLE (p), IDENTIFIER, q, NO_MOID, NORMAL_IDENTIFIER) != NO_TAG);
4319           ATTRIBUTE (q) = DEFINING_IDENTIFIER;
4320           ATTRIBUTE (FORWARD (q)) = ASSIGN_SYMBOL;
4321           q = skip_unit (q);
4322         } else {
4323           siga = A68_FALSE;
4324         }
4325       } while (siga && q != NO_NODE && IS (q, COMMA_SYMBOL));
4326     } else {
4327       FORWARD (q);
4328     }
4329   }
4330 }
4331 
4332 
4333 /**
4334 @brief Schedule gathering of definitions in a phrase.
4335 @param p Node in syntax tree.
4336 **/
4337 
4338 static void
extract_declarations(NODE_T * p)4339 extract_declarations (NODE_T * p)
4340 {
4341   NODE_T *q;
4342 /* Get definitions so we know what is defined in this range */
4343   extract_identities (p);
4344   extract_variables (p);
4345   extract_proc_identities (p);
4346   extract_proc_variables (p);
4347 /* By now we know whether "=" is an operator or not */
4348   for (q = p; q != NO_NODE; FORWARD (q)) {
4349     if (IS (q, EQUALS_SYMBOL)) {
4350       ATTRIBUTE (q) = OPERATOR;
4351     } else if (IS (q, ALT_EQUALS_SYMBOL)) {
4352       ATTRIBUTE (q) = EQUALS_SYMBOL;
4353     }
4354   }
4355 /* Get qualifiers */
4356   for (q = p; q != NO_NODE; FORWARD (q)) {
4357     if (whether (q, LOC_SYMBOL, DECLARER, DEFINING_IDENTIFIER, STOP)) {
4358       make_sub (q, q, QUALIFIER);
4359     }
4360     if (whether (q, HEAP_SYMBOL, DECLARER, DEFINING_IDENTIFIER, STOP)) {
4361       make_sub (q, q, QUALIFIER);
4362     }
4363     if (whether (q, NEW_SYMBOL, DECLARER, DEFINING_IDENTIFIER, STOP)) {
4364       make_sub (q, q, QUALIFIER);
4365     }
4366     if (whether (q, LOC_SYMBOL, PROC_SYMBOL, DEFINING_IDENTIFIER, STOP)) {
4367       make_sub (q, q, QUALIFIER);
4368     }
4369     if (whether (q, HEAP_SYMBOL, PROC_SYMBOL, DEFINING_IDENTIFIER, STOP)) {
4370       make_sub (q, q, QUALIFIER);
4371     }
4372     if (whether (q, NEW_SYMBOL, PROC_SYMBOL, DEFINING_IDENTIFIER, STOP)) {
4373       make_sub (q, q, QUALIFIER);
4374     }
4375   }
4376 /* Give priorities to operators */
4377   for (q = p; q != NO_NODE; FORWARD (q)) {
4378     if (IS (q, OPERATOR)) {
4379       if (find_tag_global (TABLE (q), OP_SYMBOL, NSYMBOL (q))) {
4380         TAG_T *s = find_tag_global (TABLE (q), PRIO_SYMBOL, NSYMBOL (q));
4381         if (s != NO_TAG) {
4382           PRIO (INFO (q)) = PRIO (s);
4383         } else {
4384           PRIO (INFO (q)) = 0;
4385         }
4386       } else {
4387         diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_UNDECLARED_TAG);
4388         PRIO (INFO (q)) = 1;
4389       }
4390     }
4391   }
4392 }
4393 
4394 /**
4395 @brief If match then reduce a sentence, the core BU parser routine.
4396 @param p Token where to start matching.
4397 @param a If not NO_NOTE, procedure to execute upon match.
4398 @param z If not NO_TICK, to be set to TRUE upon match.
4399 **/
4400 
4401 static void
reduce(NODE_T * p,void (* a)(NODE_T *),BOOL_T * z,...)4402 reduce (NODE_T * p, void (*a) (NODE_T *), BOOL_T * z, ...)
4403 {
4404   va_list list;
4405   int result, arg;
4406   NODE_T *head = p, *tail = NO_NODE;
4407   va_start (list, z);
4408   result = va_arg (list, int);
4409   while ((arg = va_arg (list, int)) != STOP)
4410   {
4411     BOOL_T keep_matching;
4412     if (p == NO_NODE) {
4413       keep_matching = A68_FALSE;
4414     } else if (arg == WILDCARD) {
4415 /* WILDCARD matches any Algol68G non terminal, but no keyword */
4416       keep_matching = (BOOL_T) (non_terminal_string (edit_line, ATTRIBUTE (p)) != NO_TEXT);
4417     } else {
4418       if (arg >= 0) {
4419         keep_matching = (BOOL_T) (arg == ATTRIBUTE (p));
4420       } else {
4421         keep_matching = (BOOL_T) (arg != ATTRIBUTE (p));
4422       }
4423     }
4424     if (keep_matching) {
4425       tail = p;
4426       FORWARD (p);
4427     } else {
4428       va_end (list);
4429       return;
4430     }
4431   }
4432 /* Print parser reductions */
4433   if (head != NO_NODE && OPTION_REDUCTIONS (&program) && LINE_NUMBER (head) > 0) {
4434     NODE_T *q;
4435     int count = 0;
4436     reductions++;
4437     WIS (head);
4438     ASSERT (snprintf (output_line, SNPRINTF_SIZE, "\nReduction %d: %s<-", reductions, non_terminal_string (edit_line, result)) >= 0);
4439     WRITE (STDOUT_FILENO, output_line);
4440     for (q = head; q != NO_NODE && tail != NO_NODE && q != NEXT (tail); FORWARD (q), count++) {
4441       int gatt = ATTRIBUTE (q);
4442       char *str = non_terminal_string (input_line, gatt);
4443       if (count > 0) {
4444         WRITE (STDOUT_FILENO, ", ");
4445       }
4446       if (str != NO_TEXT) {
4447         WRITE (STDOUT_FILENO, str);
4448         if (gatt == IDENTIFIER || gatt == OPERATOR || gatt == DENOTATION || gatt == INDICANT) {
4449           ASSERT (snprintf (output_line, SNPRINTF_SIZE, " \"%s\"", NSYMBOL (q)) >= 0);
4450           WRITE (STDOUT_FILENO, output_line);
4451         }
4452       } else {
4453         WRITE (STDOUT_FILENO, NSYMBOL (q));
4454       }
4455     }
4456   }
4457 /* Make reduction */
4458   if (a != NO_NOTE) {
4459     a (head);
4460   }
4461   make_sub (head, tail, result);
4462   va_end (list);
4463   if (z != NO_TICK) {
4464     *z = A68_TRUE;
4465   }
4466 }
4467 
4468 /**
4469 @brief Graciously ignore extra semicolons.
4470 @param p Node in syntax tree.
4471 **/
4472 
4473 static void
ignore_superfluous_semicolons(NODE_T * p)4474 ignore_superfluous_semicolons (NODE_T * p)
4475 {
4476 /*
4477 This routine relaxes the parser a bit with respect to superfluous semicolons,
4478 for instance "FI; OD". These provoke only a warning.
4479 */
4480   for (; p != NO_NODE; FORWARD (p)) {
4481     ignore_superfluous_semicolons (SUB (p));
4482     if (NEXT (p) != NO_NODE && IS (NEXT (p), SEMI_SYMBOL) && NEXT_NEXT (p) == NO_NODE) {
4483       diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, NEXT (p), WARNING_SKIPPED_SUPERFLUOUS, ATTRIBUTE (NEXT (p)));
4484       NEXT (p) = NO_NODE;
4485     } else if (IS (p, SEMI_SYMBOL) && is_semicolon_less (NEXT (p))) {
4486       diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, p, WARNING_SKIPPED_SUPERFLUOUS, ATTRIBUTE (p));
4487       if (PREVIOUS (p) != NO_NODE) {
4488         NEXT (PREVIOUS (p)) = NEXT (p);
4489       }
4490       PREVIOUS (NEXT (p)) = PREVIOUS (p);
4491     }
4492   }
4493 }
4494 
4495 /**
4496 @brief Driver for the bottom-up parser.
4497 @param p Node in syntax tree.
4498 **/
4499 
4500 void
bottom_up_parser(NODE_T * p)4501 bottom_up_parser (NODE_T * p)
4502 {
4503   if (p != NO_NODE) {
4504     if (!setjmp (bottom_up_crash_exit)) {
4505       NODE_T *q;
4506       int error_count_0 = ERROR_COUNT (&program);
4507       ignore_superfluous_semicolons (p);
4508 /* A program is "label sequence; particular program" */
4509       extract_labels (p, SERIAL_CLAUSE /* a fake here, but ok */ );
4510 /* Parse the program itself */
4511       for (q = p; q != NO_NODE; FORWARD (q)) {
4512         BOOL_T siga = A68_TRUE;
4513         if (SUB (q) != NO_NODE) {
4514           reduce_branch (q, SOME_CLAUSE);
4515         }
4516         while (siga) {
4517           siga = A68_FALSE;
4518           reduce (q, NO_NOTE, &siga, LABEL, DEFINING_IDENTIFIER, COLON_SYMBOL, STOP);
4519           reduce (q, NO_NOTE, &siga, LABEL, LABEL, DEFINING_IDENTIFIER, COLON_SYMBOL, STOP);
4520         }
4521       }
4522 /* Determine the encompassing enclosed clause */
4523       for (q = p; q != NO_NODE; FORWARD (q)) {
4524 #if defined HAVE_PARALLEL_CLAUSE
4525         reduce (q, NO_NOTE, NO_TICK, PARALLEL_CLAUSE, PAR_SYMBOL, COLLATERAL_CLAUSE, STOP);
4526 #else
4527         reduce (q, par_clause, NO_TICK, PARALLEL_CLAUSE, PAR_SYMBOL, COLLATERAL_CLAUSE, STOP);
4528 #endif
4529         reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, PARALLEL_CLAUSE, STOP);
4530         reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CLOSED_CLAUSE, STOP);
4531         reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, COLLATERAL_CLAUSE, STOP);
4532         reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CONDITIONAL_CLAUSE, STOP);
4533         reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CASE_CLAUSE, STOP);
4534         reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CONFORMITY_CLAUSE, STOP);
4535         reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, LOOP_CLAUSE, STOP);
4536       }
4537 /* Try reducing the particular program */
4538       q = p;
4539       reduce (q, NO_NOTE, NO_TICK, PARTICULAR_PROGRAM, LABEL, ENCLOSED_CLAUSE, STOP);
4540       reduce (q, NO_NOTE, NO_TICK, PARTICULAR_PROGRAM, ENCLOSED_CLAUSE, STOP);
4541       if (SUB (p) == NO_NODE || NEXT (p) != NO_NODE) {
4542         recover_from_error (p, PARTICULAR_PROGRAM, (BOOL_T) ((ERROR_COUNT (&program) - error_count_0) > MAX_ERRORS));
4543       }
4544     }
4545   }
4546 }
4547 
4548 /**
4549 @brief Reduce code clause.
4550 @param p Node in syntax tree.
4551 **/
4552 
4553 static void
reduce_code_clause(NODE_T * p)4554 reduce_code_clause (NODE_T * p)
4555 {
4556   BOOL_T siga = A68_TRUE;
4557   while (siga) {
4558     NODE_T *u;
4559     siga = A68_FALSE;
4560     for (u = p; u != NO_NODE; FORWARD (u)) {
4561       reduce (u, NO_NOTE, &siga, CODE_LIST, CODE_SYMBOL, ROW_CHAR_DENOTATION, STOP);
4562       reduce (u, NO_NOTE, &siga, CODE_LIST, CODE_LIST, ROW_CHAR_DENOTATION, STOP);
4563       reduce (u, NO_NOTE, &siga, CODE_LIST, CODE_LIST, COMMA_SYMBOL, ROW_CHAR_DENOTATION, STOP);
4564       reduce (u, NO_NOTE, &siga, CODE_CLAUSE, CODE_LIST, EDOC_SYMBOL, STOP);
4565     }
4566   }
4567 }
4568 
4569 /**
4570 @brief Reduce the sub-phrase that starts one level down.
4571 @param q Node in syntax tree.
4572 @param expect Information the parser may have on what is expected.
4573 **/
4574 
4575 static void
reduce_branch(NODE_T * q,int expect)4576 reduce_branch (NODE_T * q, int expect)
4577 {
4578 /*
4579 If this is unsuccessful then it will at least copy the resulting attribute
4580 as the parser can repair some faults. This gives less spurious diagnostics.
4581 */
4582   if (q != NO_NODE && SUB (q) != NO_NODE) {
4583     NODE_T *p = SUB (q), *u = NO_NODE;
4584     int error_count_0 = ERROR_COUNT (&program), error_count_02;
4585     BOOL_T declarer_pack = A68_FALSE, no_error;
4586     switch (expect) {
4587     case STRUCTURE_PACK:
4588     case PARAMETER_PACK:
4589     case FORMAL_DECLARERS:
4590     case UNION_PACK:
4591     case SPECIFIER:{
4592         declarer_pack = A68_TRUE;
4593       }
4594     default:{
4595         declarer_pack = A68_FALSE;
4596       }
4597     }
4598 /* Sample all info needed to decide whether a bold tag is operator or indicant.
4599    Find the meaning of bold tags and quit in case of extra errors. */
4600     extract_indicants (p);
4601     if (!declarer_pack) {
4602       extract_priorities (p);
4603       extract_operators (p);
4604     }
4605     error_count_02 = ERROR_COUNT (&program);
4606     elaborate_bold_tags (p);
4607     if ((ERROR_COUNT (&program) - error_count_02) > 0) {
4608       longjmp (bottom_up_crash_exit, 1);
4609     }
4610 /* Now we can reduce declarers, knowing which bold tags are indicants */
4611     reduce_declarers (p, expect);
4612 /* Parse the phrase, as appropriate */
4613     if (expect == CODE_CLAUSE) {
4614       reduce_code_clause (p);
4615     } else if (declarer_pack == A68_FALSE) {
4616       error_count_02 = ERROR_COUNT (&program);
4617       extract_declarations (p);
4618       if ((ERROR_COUNT (&program) - error_count_02) > 0) {
4619         longjmp (bottom_up_crash_exit, 1);
4620       }
4621       extract_labels (p, expect);
4622       for (u = p; u != NO_NODE; FORWARD (u)) {
4623         if (SUB (u) != NO_NODE) {
4624           if (IS (u, FORMAT_DELIMITER_SYMBOL)) {
4625             reduce_branch (u, FORMAT_TEXT);
4626           } else if (IS (u, FORMAT_OPEN_SYMBOL)) {
4627             reduce_branch (u, FORMAT_TEXT);
4628           } else if (IS (u, OPEN_SYMBOL)) {
4629             if (NEXT (u) != NO_NODE && IS (NEXT (u), THEN_BAR_SYMBOL)) {
4630               reduce_branch (u, ENQUIRY_CLAUSE);
4631             } else if (PREVIOUS (u) != NO_NODE && IS (PREVIOUS (u), PAR_SYMBOL)) {
4632               reduce_branch (u, COLLATERAL_CLAUSE);
4633             }
4634           } else if (is_one_of (u, IF_SYMBOL, ELIF_SYMBOL, CASE_SYMBOL, OUSE_SYMBOL, WHILE_SYMBOL, UNTIL_SYMBOL, ELSE_BAR_SYMBOL, ACCO_SYMBOL, STOP)) {
4635             reduce_branch (u, ENQUIRY_CLAUSE);
4636           } else if (IS (u, BEGIN_SYMBOL)) {
4637             reduce_branch (u, SOME_CLAUSE);
4638           } else if (is_one_of (u, THEN_SYMBOL, ELSE_SYMBOL, OUT_SYMBOL, DO_SYMBOL, ALT_DO_SYMBOL, STOP)) {
4639             reduce_branch (u, SERIAL_CLAUSE);
4640           } else if (IS (u, IN_SYMBOL)) {
4641             reduce_branch (u, COLLATERAL_CLAUSE);
4642           } else if (IS (u, THEN_BAR_SYMBOL)) {
4643             reduce_branch (u, SOME_CLAUSE);
4644           } else if (IS (u, LOOP_CLAUSE)) {
4645             reduce_branch (u, ENCLOSED_CLAUSE);
4646           } else if (is_one_of (u, FOR_SYMBOL, FROM_SYMBOL, BY_SYMBOL, TO_SYMBOL, DOWNTO_SYMBOL, STOP)) {
4647             reduce_branch (u, UNIT);
4648           }
4649         }
4650       }
4651       reduce_primary_parts (p, expect);
4652       if (expect != ENCLOSED_CLAUSE) {
4653         reduce_primaries (p, expect);
4654         if (expect == FORMAT_TEXT) {
4655           reduce_format_texts (p);
4656         } else {
4657           reduce_secondaries (p);
4658           reduce_formulae (p);
4659           reduce_tertiaries (p);
4660         }
4661       }
4662       for (u = p; u != NO_NODE; FORWARD (u)) {
4663         if (SUB (u) != NO_NODE) {
4664           if (IS (u, CODE_SYMBOL)) {
4665             reduce_branch (u, CODE_CLAUSE);
4666           }
4667         }
4668       }
4669       reduce_right_to_left_constructs (p);
4670 /* Reduce units and declarations */
4671       reduce_basic_declarations (p);
4672       reduce_units (p);
4673       reduce_erroneous_units (p);
4674       if (expect != UNIT) {
4675         if (expect == GENERIC_ARGUMENT) {
4676           reduce_generic_arguments (p);
4677         } else if (expect == BOUNDS) {
4678           reduce_bounds (p);
4679         } else {
4680           reduce_declaration_lists (p);
4681           if (expect != DECLARATION_LIST) {
4682             for (u = p; u != NO_NODE; FORWARD (u)) {
4683               reduce (u, NO_NOTE, NO_TICK, LABELED_UNIT, LABEL, UNIT, STOP);
4684               reduce (u, NO_NOTE, NO_TICK, SPECIFIED_UNIT, SPECIFIER, COLON_SYMBOL, UNIT, STOP);
4685             }
4686             if (expect == SOME_CLAUSE) {
4687               expect = serial_or_collateral (p);
4688             }
4689             if (expect == SERIAL_CLAUSE) {
4690               reduce_serial_clauses (p);
4691             } else if (expect == ENQUIRY_CLAUSE) {
4692               reduce_enquiry_clauses (p);
4693             } else if (expect == COLLATERAL_CLAUSE) {
4694               reduce_collateral_clauses (p);
4695             } else if (expect == ARGUMENT) {
4696               reduce_arguments (p);
4697             }
4698           }
4699         }
4700       }
4701       reduce_enclosed_clauses (p, expect);
4702     }
4703 /* Do something if parsing failed */
4704     if (SUB (p) == NO_NODE || NEXT (p) != NO_NODE) {
4705       recover_from_error (p, expect, (BOOL_T) ((ERROR_COUNT (&program) - error_count_0) > MAX_ERRORS));
4706       no_error = A68_FALSE;
4707     } else {
4708       no_error = A68_TRUE;
4709     }
4710     ATTRIBUTE (q) = ATTRIBUTE (p);
4711     if (no_error) {
4712       SUB (q) = SUB (p);
4713     }
4714   }
4715 }
4716 
4717 /**
4718 @brief Driver for reducing declarers.
4719 @param p Node in syntax tree.
4720 @param expect Information the parser may have on what is expected.
4721 **/
4722 
4723 static void
reduce_declarers(NODE_T * p,int expect)4724 reduce_declarers (NODE_T * p, int expect)
4725 {
4726   NODE_T *q;
4727   BOOL_T siga;
4728 /* Reduce lengtheties */
4729   for (q = p; q != NO_NODE; FORWARD (q)) {
4730     siga = A68_TRUE;
4731     reduce (q, NO_NOTE, NO_TICK, LONGETY, LONG_SYMBOL, STOP);
4732     reduce (q, NO_NOTE, NO_TICK, SHORTETY, SHORT_SYMBOL, STOP);
4733     while (siga) {
4734       siga = A68_FALSE;
4735       reduce (q, NO_NOTE, &siga, LONGETY, LONGETY, LONG_SYMBOL, STOP);
4736       reduce (q, NO_NOTE, &siga, SHORTETY, SHORTETY, SHORT_SYMBOL, STOP);
4737     }
4738   }
4739 /* Reduce indicants */
4740   for (q = p; q != NO_NODE; FORWARD (q)) {
4741     reduce (q, NO_NOTE, NO_TICK, INDICANT, INT_SYMBOL, STOP);
4742     reduce (q, NO_NOTE, NO_TICK, INDICANT, REAL_SYMBOL, STOP);
4743     reduce (q, NO_NOTE, NO_TICK, INDICANT, BITS_SYMBOL, STOP);
4744     reduce (q, NO_NOTE, NO_TICK, INDICANT, BYTES_SYMBOL, STOP);
4745     reduce (q, NO_NOTE, NO_TICK, INDICANT, COMPLEX_SYMBOL, STOP);
4746     reduce (q, NO_NOTE, NO_TICK, INDICANT, COMPL_SYMBOL, STOP);
4747     reduce (q, NO_NOTE, NO_TICK, INDICANT, BOOL_SYMBOL, STOP);
4748     reduce (q, NO_NOTE, NO_TICK, INDICANT, CHAR_SYMBOL, STOP);
4749     reduce (q, NO_NOTE, NO_TICK, INDICANT, FORMAT_SYMBOL, STOP);
4750     reduce (q, NO_NOTE, NO_TICK, INDICANT, STRING_SYMBOL, STOP);
4751     reduce (q, NO_NOTE, NO_TICK, INDICANT, FILE_SYMBOL, STOP);
4752     reduce (q, NO_NOTE, NO_TICK, INDICANT, CHANNEL_SYMBOL, STOP);
4753     reduce (q, NO_NOTE, NO_TICK, INDICANT, SEMA_SYMBOL, STOP);
4754     reduce (q, NO_NOTE, NO_TICK, INDICANT, PIPE_SYMBOL, STOP);
4755     reduce (q, NO_NOTE, NO_TICK, INDICANT, SOUND_SYMBOL, STOP);
4756   }
4757 /* Reduce standard stuff */
4758   for (q = p; q != NO_NODE; FORWARD (q)) {
4759     if (whether (q, LONGETY, INDICANT, STOP)) {
4760       int a;
4761       if (SUB_NEXT (q) == NO_NODE) {
4762         diagnostic_node (A68_SYNTAX_ERROR, NEXT (q), ERROR_EXPECTED, INFO_APPROPRIATE_DECLARER);
4763         reduce (q, NO_NOTE, NO_TICK, DECLARER, LONGETY, INDICANT, STOP);
4764       } else {
4765         a = ATTRIBUTE (SUB_NEXT (q));
4766         if (a == INT_SYMBOL || a == REAL_SYMBOL || a == BITS_SYMBOL || a == BYTES_SYMBOL || a == COMPLEX_SYMBOL || a == COMPL_SYMBOL) {
4767           reduce (q, NO_NOTE, NO_TICK, DECLARER, LONGETY, INDICANT, STOP);
4768         } else {
4769           diagnostic_node (A68_SYNTAX_ERROR, NEXT (q), ERROR_EXPECTED, INFO_APPROPRIATE_DECLARER);
4770           reduce (q, NO_NOTE, NO_TICK, DECLARER, LONGETY, INDICANT, STOP);
4771         }
4772       }
4773     } else if (whether (q, SHORTETY, INDICANT, STOP)) {
4774       int a;
4775       if (SUB_NEXT (q) == NO_NODE) {
4776         diagnostic_node (A68_SYNTAX_ERROR, NEXT (q), ERROR_EXPECTED, INFO_APPROPRIATE_DECLARER);
4777         reduce (q, NO_NOTE, NO_TICK, DECLARER, SHORTETY, INDICANT, STOP);
4778       } else {
4779         a = ATTRIBUTE (SUB_NEXT (q));
4780         if (a == INT_SYMBOL || a == REAL_SYMBOL || a == BITS_SYMBOL || a == BYTES_SYMBOL || a == COMPLEX_SYMBOL || a == COMPL_SYMBOL) {
4781           reduce (q, NO_NOTE, NO_TICK, DECLARER, SHORTETY, INDICANT, STOP);
4782         } else {
4783           diagnostic_node (A68_SYNTAX_ERROR, NEXT (q), ERROR_EXPECTED, INFO_APPROPRIATE_DECLARER);
4784           reduce (q, NO_NOTE, NO_TICK, DECLARER, LONGETY, INDICANT, STOP);
4785         }
4786       }
4787     }
4788   }
4789   for (q = p; q != NO_NODE; FORWARD (q)) {
4790     reduce (q, NO_NOTE, NO_TICK, DECLARER, INDICANT, STOP);
4791   }
4792 /* Reduce declarer lists */
4793   for (q = p; q != NO_NODE; FORWARD (q)) {
4794     if (NEXT (q) != NO_NODE && SUB_NEXT (q) != NO_NODE) {
4795       if (IS (q, STRUCT_SYMBOL)) {
4796         reduce_branch (NEXT (q), STRUCTURE_PACK);
4797         reduce (q, NO_NOTE, NO_TICK, DECLARER, STRUCT_SYMBOL, STRUCTURE_PACK, STOP);
4798       } else if (IS (q, UNION_SYMBOL)) {
4799         reduce_branch (NEXT (q), UNION_PACK);
4800         reduce (q, NO_NOTE, NO_TICK, DECLARER, UNION_SYMBOL, UNION_PACK, STOP);
4801       } else if (IS (q, PROC_SYMBOL)) {
4802         if (whether (q, PROC_SYMBOL, OPEN_SYMBOL, STOP)) {
4803           if (!is_formal_bounds (SUB_NEXT (q))) {
4804             reduce_branch (NEXT (q), FORMAL_DECLARERS);
4805           }
4806         }
4807       } else if (IS (q, OP_SYMBOL)) {
4808         if (whether (q, OP_SYMBOL, OPEN_SYMBOL, STOP)) {
4809           if (!is_formal_bounds (SUB_NEXT (q))) {
4810             reduce_branch (NEXT (q), FORMAL_DECLARERS);
4811           }
4812         }
4813       }
4814     }
4815   }
4816 /* Reduce row, proc or op declarers */
4817   siga = A68_TRUE;
4818   while (siga) {
4819     siga = A68_FALSE;
4820     for (q = p; q != NO_NODE; FORWARD (q)) {
4821 /* FLEX DECL */
4822       if (whether (q, FLEX_SYMBOL, DECLARER, STOP)) {
4823         reduce (q, NO_NOTE, &siga, DECLARER, FLEX_SYMBOL, DECLARER, STOP);
4824       }
4825 /* FLEX [] DECL */
4826       if (whether (q, FLEX_SYMBOL, SUB_SYMBOL, DECLARER, STOP) && SUB_NEXT (q) != NO_NODE) {
4827         reduce_branch (NEXT (q), BOUNDS);
4828         reduce (q, NO_NOTE, &siga, DECLARER, FLEX_SYMBOL, BOUNDS, DECLARER, STOP);
4829         reduce (q, NO_NOTE, &siga, DECLARER, FLEX_SYMBOL, FORMAL_BOUNDS, DECLARER, STOP);
4830       }
4831 /* FLEX () DECL */
4832       if (whether (q, FLEX_SYMBOL, OPEN_SYMBOL, DECLARER, STOP) && SUB_NEXT (q) != NO_NODE) {
4833         if (!whether (q, FLEX_SYMBOL, OPEN_SYMBOL, DECLARER, COLON_SYMBOL, STOP)) {
4834           reduce_branch (NEXT (q), BOUNDS);
4835           reduce (q, NO_NOTE, &siga, DECLARER, FLEX_SYMBOL, BOUNDS, DECLARER, STOP);
4836           reduce (q, NO_NOTE, &siga, DECLARER, FLEX_SYMBOL, FORMAL_BOUNDS, DECLARER, STOP);
4837         }
4838       }
4839 /* [] DECL */
4840       if (whether (q, SUB_SYMBOL, DECLARER, STOP) && SUB (q) != NO_NODE) {
4841         reduce_branch (q, BOUNDS);
4842         reduce (q, NO_NOTE, &siga, DECLARER, BOUNDS, DECLARER, STOP);
4843         reduce (q, NO_NOTE, &siga, DECLARER, FORMAL_BOUNDS, DECLARER, STOP);
4844       }
4845 /* () DECL */
4846       if (whether (q, OPEN_SYMBOL, DECLARER, STOP) && SUB (q) != NO_NODE) {
4847         if (whether (q, OPEN_SYMBOL, DECLARER, COLON_SYMBOL, STOP)) {
4848 /* Catch e.g. (INT i) () INT: */
4849           if (is_formal_bounds (SUB (q))) {
4850             reduce_branch (q, BOUNDS);
4851             reduce (q, NO_NOTE, &siga, DECLARER, BOUNDS, DECLARER, STOP);
4852             reduce (q, NO_NOTE, &siga, DECLARER, FORMAL_BOUNDS, DECLARER, STOP);
4853           }
4854         } else {
4855           reduce_branch (q, BOUNDS);
4856           reduce (q, NO_NOTE, &siga, DECLARER, BOUNDS, DECLARER, STOP);
4857           reduce (q, NO_NOTE, &siga, DECLARER, FORMAL_BOUNDS, DECLARER, STOP);
4858         }
4859       }
4860     }
4861 /* PROC DECL, PROC () DECL, OP () DECL */
4862     for (q = p; q != NO_NODE; FORWARD (q)) {
4863       int a = ATTRIBUTE (q);
4864       if (a == REF_SYMBOL) {
4865         reduce (q, NO_NOTE, &siga, DECLARER, REF_SYMBOL, DECLARER, STOP);
4866       } else if (a == PROC_SYMBOL) {
4867         reduce (q, NO_NOTE, &siga, DECLARER, PROC_SYMBOL, DECLARER, STOP);
4868         reduce (q, NO_NOTE, &siga, DECLARER, PROC_SYMBOL, FORMAL_DECLARERS, DECLARER, STOP);
4869         reduce (q, NO_NOTE, &siga, DECLARER, PROC_SYMBOL, VOID_SYMBOL, STOP);
4870         reduce (q, NO_NOTE, &siga, DECLARER, PROC_SYMBOL, FORMAL_DECLARERS, VOID_SYMBOL, STOP);
4871       } else if (a == OP_SYMBOL) {
4872         reduce (q, NO_NOTE, &siga, OPERATOR_PLAN, OP_SYMBOL, FORMAL_DECLARERS, DECLARER, STOP);
4873         reduce (q, NO_NOTE, &siga, OPERATOR_PLAN, OP_SYMBOL, FORMAL_DECLARERS, VOID_SYMBOL, STOP);
4874       }
4875     }
4876   }
4877 /* Reduce packs etcetera */
4878   if (expect == STRUCTURE_PACK) {
4879     for (q = p; q != NO_NODE; FORWARD (q)) {
4880       siga = A68_TRUE;
4881       while (siga) {
4882         siga = A68_FALSE;
4883         reduce (q, NO_NOTE, &siga, STRUCTURED_FIELD, DECLARER, IDENTIFIER, STOP);
4884         reduce (q, NO_NOTE, &siga, STRUCTURED_FIELD, STRUCTURED_FIELD, COMMA_SYMBOL, IDENTIFIER, STOP);
4885       }
4886     }
4887     for (q = p; q != NO_NODE; FORWARD (q)) {
4888       siga = A68_TRUE;
4889       while (siga) {
4890         siga = A68_FALSE;
4891         reduce (q, NO_NOTE, &siga, STRUCTURED_FIELD_LIST, STRUCTURED_FIELD, STOP);
4892         reduce (q, NO_NOTE, &siga, STRUCTURED_FIELD_LIST, STRUCTURED_FIELD_LIST, COMMA_SYMBOL, STRUCTURED_FIELD, STOP);
4893         reduce (q, strange_separator, &siga, STRUCTURED_FIELD_LIST, STRUCTURED_FIELD_LIST, STRUCTURED_FIELD, STOP);
4894         reduce (q, strange_separator, &siga, STRUCTURED_FIELD_LIST, STRUCTURED_FIELD_LIST, SEMI_SYMBOL, STRUCTURED_FIELD, STOP);
4895       }
4896     }
4897     q = p;
4898     reduce (q, NO_NOTE, NO_TICK, STRUCTURE_PACK, OPEN_SYMBOL, STRUCTURED_FIELD_LIST, CLOSE_SYMBOL, STOP);
4899   } else if (expect == PARAMETER_PACK) {
4900     for (q = p; q != NO_NODE; FORWARD (q)) {
4901       siga = A68_TRUE;
4902       while (siga) {
4903         siga = A68_FALSE;
4904         reduce (q, NO_NOTE, &siga, PARAMETER, DECLARER, IDENTIFIER, STOP);
4905         reduce (q, NO_NOTE, &siga, PARAMETER, PARAMETER, COMMA_SYMBOL, IDENTIFIER, STOP);
4906       }
4907     }
4908     for (q = p; q != NO_NODE; FORWARD (q)) {
4909       siga = A68_TRUE;
4910       while (siga) {
4911         siga = A68_FALSE;
4912         reduce (q, NO_NOTE, &siga, PARAMETER_LIST, PARAMETER, STOP);
4913         reduce (q, NO_NOTE, &siga, PARAMETER_LIST, PARAMETER_LIST, COMMA_SYMBOL, PARAMETER, STOP);
4914       }
4915     }
4916     q = p;
4917     reduce (q, NO_NOTE, NO_TICK, PARAMETER_PACK, OPEN_SYMBOL, PARAMETER_LIST, CLOSE_SYMBOL, STOP);
4918   } else if (expect == FORMAL_DECLARERS) {
4919     for (q = p; q != NO_NODE; FORWARD (q)) {
4920       siga = A68_TRUE;
4921       while (siga) {
4922         siga = A68_FALSE;
4923         reduce (q, NO_NOTE, &siga, FORMAL_DECLARERS_LIST, DECLARER, STOP);
4924         reduce (q, NO_NOTE, &siga, FORMAL_DECLARERS_LIST, FORMAL_DECLARERS_LIST, COMMA_SYMBOL, DECLARER, STOP);
4925         reduce (q, strange_separator, &siga, FORMAL_DECLARERS_LIST, FORMAL_DECLARERS_LIST, SEMI_SYMBOL, DECLARER, STOP);
4926         reduce (q, strange_separator, &siga, FORMAL_DECLARERS_LIST, FORMAL_DECLARERS_LIST, DECLARER, STOP);
4927       }
4928     }
4929     q = p;
4930     reduce (q, NO_NOTE, NO_TICK, FORMAL_DECLARERS, OPEN_SYMBOL, FORMAL_DECLARERS_LIST, CLOSE_SYMBOL, STOP);
4931   } else if (expect == UNION_PACK) {
4932     for (q = p; q != NO_NODE; FORWARD (q)) {
4933       siga = A68_TRUE;
4934       while (siga) {
4935         siga = A68_FALSE;
4936         reduce (q, NO_NOTE, &siga, UNION_DECLARER_LIST, DECLARER, STOP);
4937         reduce (q, NO_NOTE, &siga, UNION_DECLARER_LIST, VOID_SYMBOL, STOP);
4938         reduce (q, NO_NOTE, &siga, UNION_DECLARER_LIST, UNION_DECLARER_LIST, COMMA_SYMBOL, DECLARER, STOP);
4939         reduce (q, NO_NOTE, &siga, UNION_DECLARER_LIST, UNION_DECLARER_LIST, COMMA_SYMBOL, VOID_SYMBOL, STOP);
4940         reduce (q, strange_separator, &siga, UNION_DECLARER_LIST, UNION_DECLARER_LIST, SEMI_SYMBOL, DECLARER, STOP);
4941         reduce (q, strange_separator, &siga, UNION_DECLARER_LIST, UNION_DECLARER_LIST, SEMI_SYMBOL, VOID_SYMBOL, STOP);
4942         reduce (q, strange_separator, &siga, UNION_DECLARER_LIST, UNION_DECLARER_LIST, DECLARER, STOP);
4943         reduce (q, strange_separator, &siga, UNION_DECLARER_LIST, UNION_DECLARER_LIST, VOID_SYMBOL, STOP);
4944       }
4945     }
4946     q = p;
4947     reduce (q, NO_NOTE, NO_TICK, UNION_PACK, OPEN_SYMBOL, UNION_DECLARER_LIST, CLOSE_SYMBOL, STOP);
4948   } else if (expect == SPECIFIER) {
4949     reduce (p, NO_NOTE, NO_TICK, SPECIFIER, OPEN_SYMBOL, DECLARER, IDENTIFIER, CLOSE_SYMBOL, STOP);
4950     reduce (p, NO_NOTE, NO_TICK, SPECIFIER, OPEN_SYMBOL, DECLARER, CLOSE_SYMBOL, STOP);
4951     reduce (p, NO_NOTE, NO_TICK, SPECIFIER, OPEN_SYMBOL, VOID_SYMBOL, CLOSE_SYMBOL, STOP);
4952   } else {
4953     for (q = p; q != NO_NODE; FORWARD (q)) {
4954       if (whether (q, OPEN_SYMBOL, COLON_SYMBOL, STOP) && !(expect == GENERIC_ARGUMENT || expect == BOUNDS)) {
4955         if (is_one_of (p, IN_SYMBOL, THEN_BAR_SYMBOL, STOP)) {
4956           reduce_branch (q, SPECIFIER);
4957         }
4958       }
4959       if (whether (q, OPEN_SYMBOL, DECLARER, COLON_SYMBOL, STOP)) {
4960         reduce_branch (q, PARAMETER_PACK);
4961       }
4962       if (whether (q, OPEN_SYMBOL, VOID_SYMBOL, COLON_SYMBOL, STOP)) {
4963         reduce_branch (q, PARAMETER_PACK);
4964       }
4965     }
4966   }
4967 }
4968 
4969 /**
4970 @brief Handle cases that need reducing from right-to-left.
4971 @param p Node in syntax tree.
4972 **/
4973 
4974 static void
reduce_right_to_left_constructs(NODE_T * p)4975 reduce_right_to_left_constructs (NODE_T * p)
4976 {
4977 /*
4978 Here are cases that need reducing from right-to-left whereas many things
4979 can be reduced left-to-right. Assignations are a notable example; one could
4980 discuss whether it would not be more natural to write 1 =: k in stead of
4981 k := 1. The latter is said to be more natural, or it could be just computing
4982 history. Meanwhile we use this routine.
4983 */
4984   if (p != NO_NODE) {
4985     reduce_right_to_left_constructs (NEXT (p));
4986 /* Assignations */
4987     if (IS (p, TERTIARY)) {
4988       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, TERTIARY, STOP);
4989       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, IDENTITY_RELATION, STOP);
4990       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, AND_FUNCTION, STOP);
4991       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, OR_FUNCTION, STOP);
4992       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, ROUTINE_TEXT, STOP);
4993       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, JUMP, STOP);
4994       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, SKIP, STOP);
4995       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, ASSIGNATION, STOP);
4996       reduce (p, NO_NOTE, NO_TICK, ASSIGNATION, TERTIARY, ASSIGN_SYMBOL, CODE_CLAUSE, STOP);
4997     }
4998 /* Routine texts with parameter pack */
4999     else if (IS (p, PARAMETER_PACK)) {
5000       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, ASSIGNATION, STOP);
5001       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, IDENTITY_RELATION, STOP);
5002       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, AND_FUNCTION, STOP);
5003       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, OR_FUNCTION, STOP);
5004       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, JUMP, STOP);
5005       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, SKIP, STOP);
5006       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, TERTIARY, STOP);
5007       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, ROUTINE_TEXT, STOP);
5008       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, DECLARER, COLON_SYMBOL, CODE_CLAUSE, STOP);
5009       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, ASSIGNATION, STOP);
5010       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, IDENTITY_RELATION, STOP);
5011       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, AND_FUNCTION, STOP);
5012       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, OR_FUNCTION, STOP);
5013       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, JUMP, STOP);
5014       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, SKIP, STOP);
5015       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, TERTIARY, STOP);
5016       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, ROUTINE_TEXT, STOP);
5017       reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, PARAMETER_PACK, VOID_SYMBOL, COLON_SYMBOL, CODE_CLAUSE, STOP);
5018     }
5019 /* Routine texts without parameter pack */
5020     else if (IS (p, DECLARER)) {
5021       if (!(PREVIOUS (p) != NO_NODE && IS (PREVIOUS (p), PARAMETER_PACK))) {
5022         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, ASSIGNATION, STOP);
5023         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, IDENTITY_RELATION, STOP);
5024         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, AND_FUNCTION, STOP);
5025         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, OR_FUNCTION, STOP);
5026         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, JUMP, STOP);
5027         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, SKIP, STOP);
5028         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, TERTIARY, STOP);
5029         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, ROUTINE_TEXT, STOP);
5030         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, DECLARER, COLON_SYMBOL, CODE_CLAUSE, STOP);
5031       }
5032     } else if (IS (p, VOID_SYMBOL)) {
5033       if (!(PREVIOUS (p) != NO_NODE && IS (PREVIOUS (p), PARAMETER_PACK))) {
5034         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, ASSIGNATION, STOP);
5035         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, IDENTITY_RELATION, STOP);
5036         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, AND_FUNCTION, STOP);
5037         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, OR_FUNCTION, STOP);
5038         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, JUMP, STOP);
5039         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, SKIP, STOP);
5040         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, TERTIARY, STOP);
5041         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, ROUTINE_TEXT, STOP);
5042         reduce (p, NO_NOTE, NO_TICK, ROUTINE_TEXT, VOID_SYMBOL, COLON_SYMBOL, CODE_CLAUSE, STOP);
5043       }
5044     }
5045   }
5046 }
5047 
5048 /**
5049 @brief Reduce primary elements.
5050 @param p Node in syntax tree.
5051 @param expect Information the parser may have on what is expected.
5052 **/
5053 
5054 static void
reduce_primary_parts(NODE_T * p,int expect)5055 reduce_primary_parts (NODE_T * p, int expect)
5056 {
5057   NODE_T *q = p;
5058   for (; q != NO_NODE; FORWARD (q)) {
5059     if (whether (q, IDENTIFIER, OF_SYMBOL, STOP)) {
5060       ATTRIBUTE (q) = FIELD_IDENTIFIER;
5061     }
5062     reduce (q, NO_NOTE, NO_TICK, ENVIRON_NAME, ENVIRON_SYMBOL, ROW_CHAR_DENOTATION, STOP);
5063     reduce (q, NO_NOTE, NO_TICK, NIHIL, NIL_SYMBOL, STOP);
5064     reduce (q, NO_NOTE, NO_TICK, SKIP, SKIP_SYMBOL, STOP);
5065     reduce (q, NO_NOTE, NO_TICK, SELECTOR, FIELD_IDENTIFIER, OF_SYMBOL, STOP);
5066 /* JUMPs without GOTO are resolved later */
5067     reduce (q, NO_NOTE, NO_TICK, JUMP, GOTO_SYMBOL, IDENTIFIER, STOP);
5068     reduce (q, NO_NOTE, NO_TICK, DENOTATION, LONGETY, INT_DENOTATION, STOP);
5069     reduce (q, NO_NOTE, NO_TICK, DENOTATION, LONGETY, REAL_DENOTATION, STOP);
5070     reduce (q, NO_NOTE, NO_TICK, DENOTATION, LONGETY, BITS_DENOTATION, STOP);
5071     reduce (q, NO_NOTE, NO_TICK, DENOTATION, SHORTETY, INT_DENOTATION, STOP);
5072     reduce (q, NO_NOTE, NO_TICK, DENOTATION, SHORTETY, REAL_DENOTATION, STOP);
5073     reduce (q, NO_NOTE, NO_TICK, DENOTATION, SHORTETY, BITS_DENOTATION, STOP);
5074     reduce (q, NO_NOTE, NO_TICK, DENOTATION, INT_DENOTATION, STOP);
5075     reduce (q, NO_NOTE, NO_TICK, DENOTATION, REAL_DENOTATION, STOP);
5076     reduce (q, NO_NOTE, NO_TICK, DENOTATION, BITS_DENOTATION, STOP);
5077     reduce (q, NO_NOTE, NO_TICK, DENOTATION, ROW_CHAR_DENOTATION, STOP);
5078     reduce (q, NO_NOTE, NO_TICK, DENOTATION, TRUE_SYMBOL, STOP);
5079     reduce (q, NO_NOTE, NO_TICK, DENOTATION, FALSE_SYMBOL, STOP);
5080     reduce (q, NO_NOTE, NO_TICK, DENOTATION, EMPTY_SYMBOL, STOP);
5081     if (expect == SERIAL_CLAUSE || expect == ENQUIRY_CLAUSE || expect == SOME_CLAUSE) {
5082       BOOL_T siga = A68_TRUE;
5083       while (siga) {
5084         siga = A68_FALSE;
5085         reduce (q, NO_NOTE, &siga, LABEL, DEFINING_IDENTIFIER, COLON_SYMBOL, STOP);
5086         reduce (q, NO_NOTE, &siga, LABEL, LABEL, DEFINING_IDENTIFIER, COLON_SYMBOL, STOP);
5087       }
5088     }
5089   }
5090   for (q = p; q != NO_NODE; FORWARD (q)) {
5091 #if defined HAVE_PARALLEL_CLAUSE
5092     reduce (q, NO_NOTE, NO_TICK, PARALLEL_CLAUSE, PAR_SYMBOL, COLLATERAL_CLAUSE, STOP);
5093 #else
5094     reduce (q, par_clause, NO_TICK, PARALLEL_CLAUSE, PAR_SYMBOL, COLLATERAL_CLAUSE, STOP);
5095 #endif
5096     reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, PARALLEL_CLAUSE, STOP);
5097     reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CLOSED_CLAUSE, STOP);
5098     reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, COLLATERAL_CLAUSE, STOP);
5099     reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CONDITIONAL_CLAUSE, STOP);
5100     reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CASE_CLAUSE, STOP);
5101     reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CONFORMITY_CLAUSE, STOP);
5102     reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, LOOP_CLAUSE, STOP);
5103   }
5104 }
5105 
5106 /**
5107 @brief Reduce primaries completely.
5108 @param p Node in syntax tree.
5109 @param expect Information the parser may have on what is expected.
5110 **/
5111 
5112 static void
reduce_primaries(NODE_T * p,int expect)5113 reduce_primaries (NODE_T * p, int expect)
5114 {
5115   NODE_T *q = p;
5116   while (q != NO_NODE) {
5117     BOOL_T fwd = A68_TRUE, siga;
5118 /* Primaries excepts call and slice */
5119     reduce (q, NO_NOTE, NO_TICK, PRIMARY, IDENTIFIER, STOP);
5120     reduce (q, NO_NOTE, NO_TICK, PRIMARY, DENOTATION, STOP);
5121     reduce (q, NO_NOTE, NO_TICK, CAST, DECLARER, ENCLOSED_CLAUSE, STOP);
5122     reduce (q, NO_NOTE, NO_TICK, CAST, VOID_SYMBOL, ENCLOSED_CLAUSE, STOP);
5123     reduce (q, NO_NOTE, NO_TICK, ASSERTION, ASSERT_SYMBOL, ENCLOSED_CLAUSE, STOP);
5124     reduce (q, NO_NOTE, NO_TICK, PRIMARY, CAST, STOP);
5125     reduce (q, NO_NOTE, NO_TICK, PRIMARY, ENCLOSED_CLAUSE, STOP);
5126     reduce (q, NO_NOTE, NO_TICK, PRIMARY, FORMAT_TEXT, STOP);
5127 /* Call and slice */
5128     siga = A68_TRUE;
5129     while (siga) {
5130       NODE_T *x = NEXT (q);
5131       siga = A68_FALSE;
5132       if (IS (q, PRIMARY) && x != NO_NODE) {
5133         if (IS (x, OPEN_SYMBOL)) {
5134           reduce_branch (NEXT (q), GENERIC_ARGUMENT);
5135           reduce (q, NO_NOTE, &siga, SPECIFICATION, PRIMARY, GENERIC_ARGUMENT, STOP);
5136           reduce (q, NO_NOTE, &siga, PRIMARY, SPECIFICATION, STOP);
5137         } else if (IS (x, SUB_SYMBOL)) {
5138           reduce_branch (NEXT (q), GENERIC_ARGUMENT);
5139           reduce (q, NO_NOTE, &siga, SPECIFICATION, PRIMARY, GENERIC_ARGUMENT, STOP);
5140           reduce (q, NO_NOTE, &siga, PRIMARY, SPECIFICATION, STOP);
5141         }
5142       }
5143     }
5144 /* Now that call and slice are known, reduce remaining ( .. ) */
5145     if (IS (q, OPEN_SYMBOL) && SUB (q) != NO_NODE) {
5146       reduce_branch (q, SOME_CLAUSE);
5147       reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CLOSED_CLAUSE, STOP);
5148       reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, COLLATERAL_CLAUSE, STOP);
5149       reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CONDITIONAL_CLAUSE, STOP);
5150       reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CASE_CLAUSE, STOP);
5151       reduce (q, NO_NOTE, NO_TICK, ENCLOSED_CLAUSE, CONFORMITY_CLAUSE, STOP);
5152       if (PREVIOUS (q) != NO_NODE) {
5153         BACKWARD (q);
5154         fwd = A68_FALSE;
5155       }
5156     }
5157 /* Format text items */
5158     if (expect == FORMAT_TEXT) {
5159       NODE_T *r;
5160       for (r = p; r != NO_NODE; FORWARD (r)) {
5161         reduce (r, NO_NOTE, NO_TICK, DYNAMIC_REPLICATOR, FORMAT_ITEM_N, ENCLOSED_CLAUSE, STOP);
5162         reduce (r, NO_NOTE, NO_TICK, GENERAL_PATTERN, FORMAT_ITEM_G, ENCLOSED_CLAUSE, STOP);
5163         reduce (r, NO_NOTE, NO_TICK, GENERAL_PATTERN, FORMAT_ITEM_H, ENCLOSED_CLAUSE, STOP);
5164         reduce (r, NO_NOTE, NO_TICK, FORMAT_PATTERN, FORMAT_ITEM_F, ENCLOSED_CLAUSE, STOP);
5165       }
5166     }
5167     if (fwd) {
5168       FORWARD (q);
5169     }
5170   }
5171 }
5172 
5173 /**
5174 @brief Enforce that ambiguous patterns are separated by commas.
5175 @param p Node in syntax tree.
5176 **/
5177 
5178 static void
ambiguous_patterns(NODE_T * p)5179 ambiguous_patterns (NODE_T * p)
5180 {
5181 /*
5182 Example: printf (($+d.2d +d.2d$, 1, 2)) can produce either "+1.00 +2.00" or
5183 "+1+002.00". A comma must be supplied to resolve the ambiguity.
5184 
5185 The obvious thing would be to weave this into the syntax, letting the BU parser
5186 sort it out. But the C-style patterns do not suffer from Algol 68 pattern
5187 ambiguity, so by solving it this way we maximise freedom in writing the patterns
5188 as we want without introducing two "kinds" of patterns, and so we have shorter
5189 routines for implementing formatted transput. This is a pragmatic system.
5190 */
5191   NODE_T *q, *last_pat = NO_NODE;
5192   for (q = p; q != NO_NODE; FORWARD (q)) {
5193     switch (ATTRIBUTE (q)) {
5194     case INTEGRAL_PATTERN:     /* These are the potentially ambiguous patterns */
5195     case REAL_PATTERN:
5196     case COMPLEX_PATTERN:
5197     case BITS_PATTERN:
5198       {
5199         if (last_pat != NO_NODE) {
5200           diagnostic_node (A68_SYNTAX_ERROR, q, ERROR_COMMA_MUST_SEPARATE, ATTRIBUTE (last_pat), ATTRIBUTE (q));
5201         }
5202         last_pat = q;
5203         break;
5204       }
5205     case COMMA_SYMBOL:
5206       {
5207         last_pat = NO_NODE;
5208         break;
5209       }
5210     }
5211   }
5212 }
5213 
5214 /**
5215 @brief Reduce format texts completely.
5216 @param p Node in syntax tree.
5217 @param pr Production rule.
5218 @param let Letter.
5219 **/
5220 
5221 void
reduce_c_pattern(NODE_T * p,int pr,int let)5222 reduce_c_pattern (NODE_T * p, int pr, int let)
5223 {
5224   NODE_T *q;
5225   for (q = p; q != NO_NODE; FORWARD (q)) {
5226     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, let, STOP);
5227     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_POINT, REPLICATOR, let, STOP);
5228     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, REPLICATOR, let, STOP);
5229     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, REPLICATOR, FORMAT_ITEM_POINT, REPLICATOR, let, STOP);
5230     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_PLUS, let, STOP);
5231     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_PLUS, FORMAT_ITEM_POINT, REPLICATOR, let, STOP);
5232     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_PLUS, REPLICATOR, let, STOP);
5233     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_PLUS, REPLICATOR, FORMAT_ITEM_POINT, REPLICATOR, let, STOP);
5234     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_MINUS, let, STOP);
5235     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_MINUS, FORMAT_ITEM_POINT, REPLICATOR, let, STOP);
5236     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_MINUS, REPLICATOR, let, STOP);
5237     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_MINUS, REPLICATOR, FORMAT_ITEM_POINT, REPLICATOR, let, STOP);
5238     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_MINUS, FORMAT_ITEM_PLUS, let, STOP);
5239     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_MINUS, FORMAT_ITEM_PLUS, FORMAT_ITEM_POINT, REPLICATOR, let, STOP);
5240     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_MINUS, FORMAT_ITEM_PLUS, REPLICATOR, let, STOP);
5241     reduce (q, NO_NOTE, NO_TICK, pr, FORMAT_ITEM_ESCAPE, FORMAT_ITEM_MINUS, FORMAT_ITEM_PLUS, REPLICATOR, FORMAT_ITEM_POINT, REPLICATOR, let, STOP);
5242   }
5243 }
5244 
5245 /**
5246 @brief Reduce format texts completely.
5247 @param p Node in syntax tree.
5248 **/
5249 
5250 static void
reduce_format_texts(NODE_T * p)5251 reduce_format_texts (NODE_T * p)
5252 {
5253   NODE_T *q;
5254 /* Replicators */
5255   for (q = p; q != NO_NODE; FORWARD (q)) {
5256     reduce (q, NO_NOTE, NO_TICK, REPLICATOR, STATIC_REPLICATOR, STOP);
5257     reduce (q, NO_NOTE, NO_TICK, REPLICATOR, DYNAMIC_REPLICATOR, STOP);
5258   }
5259 /* "OTHER" patterns */
5260   reduce_c_pattern (p, BITS_C_PATTERN, FORMAT_ITEM_B);
5261   reduce_c_pattern (p, BITS_C_PATTERN, FORMAT_ITEM_O);
5262   reduce_c_pattern (p, BITS_C_PATTERN, FORMAT_ITEM_X);
5263   reduce_c_pattern (p, CHAR_C_PATTERN, FORMAT_ITEM_C);
5264   reduce_c_pattern (p, FIXED_C_PATTERN, FORMAT_ITEM_F);
5265   reduce_c_pattern (p, FLOAT_C_PATTERN, FORMAT_ITEM_E);
5266   reduce_c_pattern (p, GENERAL_C_PATTERN, FORMAT_ITEM_G);
5267   reduce_c_pattern (p, INTEGRAL_C_PATTERN, FORMAT_ITEM_D);
5268   reduce_c_pattern (p, INTEGRAL_C_PATTERN, FORMAT_ITEM_I);
5269   reduce_c_pattern (p, STRING_C_PATTERN, FORMAT_ITEM_S);
5270 /* Radix frames */
5271   for (q = p; q != NO_NODE; FORWARD (q)) {
5272     reduce (q, NO_NOTE, NO_TICK, RADIX_FRAME, REPLICATOR, FORMAT_ITEM_R, STOP);
5273   }
5274 /* Insertions */
5275   for (q = p; q != NO_NODE; FORWARD (q)) {
5276     reduce (q, NO_NOTE, NO_TICK, INSERTION, FORMAT_ITEM_X, STOP);
5277     reduce (q, NO_NOTE, NO_TICK, INSERTION, FORMAT_ITEM_Y, STOP);
5278     reduce (q, NO_NOTE, NO_TICK, INSERTION, FORMAT_ITEM_L, STOP);
5279     reduce (q, NO_NOTE, NO_TICK, INSERTION, FORMAT_ITEM_P, STOP);
5280     reduce (q, NO_NOTE, NO_TICK, INSERTION, FORMAT_ITEM_Q, STOP);
5281     reduce (q, NO_NOTE, NO_TICK, INSERTION, FORMAT_ITEM_K, STOP);
5282     reduce (q, NO_NOTE, NO_TICK, INSERTION, LITERAL, STOP);
5283   }
5284   for (q = p; q != NO_NODE; FORWARD (q)) {
5285     reduce (q, NO_NOTE, NO_TICK, INSERTION, REPLICATOR, INSERTION, STOP);
5286   }
5287   for (q = p; q != NO_NODE; FORWARD (q)) {
5288     BOOL_T siga = A68_TRUE;
5289     while (siga) {
5290       siga = A68_FALSE;
5291       reduce (q, NO_NOTE, &siga, INSERTION, INSERTION, INSERTION, STOP);
5292     }
5293   }
5294 /* Replicated suppressible frames */
5295   for (q = p; q != NO_NODE; FORWARD (q)) {
5296     reduce (q, NO_NOTE, NO_TICK, FORMAT_A_FRAME, REPLICATOR, FORMAT_ITEM_S, FORMAT_ITEM_A, STOP);
5297     reduce (q, NO_NOTE, NO_TICK, FORMAT_Z_FRAME, REPLICATOR, FORMAT_ITEM_S, FORMAT_ITEM_Z, STOP);
5298     reduce (q, NO_NOTE, NO_TICK, FORMAT_D_FRAME, REPLICATOR, FORMAT_ITEM_S, FORMAT_ITEM_D, STOP);
5299   }
5300 /* Suppressible frames */
5301   for (q = p; q != NO_NODE; FORWARD (q)) {
5302     reduce (q, NO_NOTE, NO_TICK, FORMAT_A_FRAME, FORMAT_ITEM_S, FORMAT_ITEM_A, STOP);
5303     reduce (q, NO_NOTE, NO_TICK, FORMAT_Z_FRAME, FORMAT_ITEM_S, FORMAT_ITEM_Z, STOP);
5304     reduce (q, NO_NOTE, NO_TICK, FORMAT_D_FRAME, FORMAT_ITEM_S, FORMAT_ITEM_D, STOP);
5305     reduce (q, NO_NOTE, NO_TICK, FORMAT_E_FRAME, FORMAT_ITEM_S, FORMAT_ITEM_E, STOP);
5306     reduce (q, NO_NOTE, NO_TICK, FORMAT_POINT_FRAME, FORMAT_ITEM_S, FORMAT_ITEM_POINT, STOP);
5307     reduce (q, NO_NOTE, NO_TICK, FORMAT_I_FRAME, FORMAT_ITEM_S, FORMAT_ITEM_I, STOP);
5308   }
5309 /* Replicated frames */
5310   for (q = p; q != NO_NODE; FORWARD (q)) {
5311     reduce (q, NO_NOTE, NO_TICK, FORMAT_A_FRAME, REPLICATOR, FORMAT_ITEM_A, STOP);
5312     reduce (q, NO_NOTE, NO_TICK, FORMAT_Z_FRAME, REPLICATOR, FORMAT_ITEM_Z, STOP);
5313     reduce (q, NO_NOTE, NO_TICK, FORMAT_D_FRAME, REPLICATOR, FORMAT_ITEM_D, STOP);
5314   }
5315 /* Frames */
5316   for (q = p; q != NO_NODE; FORWARD (q)) {
5317     reduce (q, NO_NOTE, NO_TICK, FORMAT_A_FRAME, FORMAT_ITEM_A, STOP);
5318     reduce (q, NO_NOTE, NO_TICK, FORMAT_Z_FRAME, FORMAT_ITEM_Z, STOP);
5319     reduce (q, NO_NOTE, NO_TICK, FORMAT_D_FRAME, FORMAT_ITEM_D, STOP);
5320     reduce (q, NO_NOTE, NO_TICK, FORMAT_E_FRAME, FORMAT_ITEM_E, STOP);
5321     reduce (q, NO_NOTE, NO_TICK, FORMAT_POINT_FRAME, FORMAT_ITEM_POINT, STOP);
5322     reduce (q, NO_NOTE, NO_TICK, FORMAT_I_FRAME, FORMAT_ITEM_I, STOP);
5323   }
5324 /* Frames with an insertion */
5325   for (q = p; q != NO_NODE; FORWARD (q)) {
5326     reduce (q, NO_NOTE, NO_TICK, FORMAT_A_FRAME, INSERTION, FORMAT_A_FRAME, STOP);
5327     reduce (q, NO_NOTE, NO_TICK, FORMAT_Z_FRAME, INSERTION, FORMAT_Z_FRAME, STOP);
5328     reduce (q, NO_NOTE, NO_TICK, FORMAT_D_FRAME, INSERTION, FORMAT_D_FRAME, STOP);
5329     reduce (q, NO_NOTE, NO_TICK, FORMAT_E_FRAME, INSERTION, FORMAT_E_FRAME, STOP);
5330     reduce (q, NO_NOTE, NO_TICK, FORMAT_POINT_FRAME, INSERTION, FORMAT_POINT_FRAME, STOP);
5331     reduce (q, NO_NOTE, NO_TICK, FORMAT_I_FRAME, INSERTION, FORMAT_I_FRAME, STOP);
5332   }
5333 /* String patterns */
5334   for (q = p; q != NO_NODE; FORWARD (q)) {
5335     reduce (q, NO_NOTE, NO_TICK, STRING_PATTERN, REPLICATOR, FORMAT_A_FRAME, STOP);
5336   }
5337   for (q = p; q != NO_NODE; FORWARD (q)) {
5338     reduce (q, NO_NOTE, NO_TICK, STRING_PATTERN, FORMAT_A_FRAME, STOP);
5339   }
5340   for (q = p; q != NO_NODE; FORWARD (q)) {
5341     BOOL_T siga = A68_TRUE;
5342     while (siga) {
5343       siga = A68_FALSE;
5344       reduce (q, NO_NOTE, &siga, STRING_PATTERN, STRING_PATTERN, STRING_PATTERN, STOP);
5345       reduce (q, NO_NOTE, &siga, STRING_PATTERN, STRING_PATTERN, INSERTION, STRING_PATTERN, STOP);
5346     }
5347   }
5348 /* Integral moulds */
5349   for (q = p; q != NO_NODE; FORWARD (q)) {
5350     reduce (q, NO_NOTE, NO_TICK, INTEGRAL_MOULD, FORMAT_Z_FRAME, STOP);
5351     reduce (q, NO_NOTE, NO_TICK, INTEGRAL_MOULD, FORMAT_D_FRAME, STOP);
5352   }
5353   for (q = p; q != NO_NODE; FORWARD (q)) {
5354     BOOL_T siga = A68_TRUE;
5355     while (siga) {
5356       siga = A68_FALSE;
5357       reduce (q, NO_NOTE, &siga, INTEGRAL_MOULD, INTEGRAL_MOULD, INTEGRAL_MOULD, STOP);
5358       reduce (q, NO_NOTE, &siga, INTEGRAL_MOULD, INTEGRAL_MOULD, INSERTION, STOP);
5359     }
5360   }
5361 /* Sign moulds */
5362   for (q = p; q != NO_NODE; FORWARD (q)) {
5363     reduce (q, NO_NOTE, NO_TICK, SIGN_MOULD, INTEGRAL_MOULD, FORMAT_ITEM_PLUS, STOP);
5364     reduce (q, NO_NOTE, NO_TICK, SIGN_MOULD, INTEGRAL_MOULD, FORMAT_ITEM_MINUS, STOP);
5365   }
5366   for (q = p; q != NO_NODE; FORWARD (q)) {
5367     reduce (q, NO_NOTE, NO_TICK, SIGN_MOULD, FORMAT_ITEM_PLUS, STOP);
5368     reduce (q, NO_NOTE, NO_TICK, SIGN_MOULD, FORMAT_ITEM_MINUS, STOP);
5369   }
5370 /* Exponent frames */
5371   for (q = p; q != NO_NODE; FORWARD (q)) {
5372     reduce (q, NO_NOTE, NO_TICK, EXPONENT_FRAME, FORMAT_E_FRAME, SIGN_MOULD, INTEGRAL_MOULD, STOP);
5373     reduce (q, NO_NOTE, NO_TICK, EXPONENT_FRAME, FORMAT_E_FRAME, INTEGRAL_MOULD, STOP);
5374   }
5375 /* Real patterns */
5376   for (q = p; q != NO_NODE; FORWARD (q)) {
5377     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, INTEGRAL_MOULD, FORMAT_POINT_FRAME, INTEGRAL_MOULD, EXPONENT_FRAME, STOP);
5378     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, INTEGRAL_MOULD, FORMAT_POINT_FRAME, INTEGRAL_MOULD, STOP);
5379     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, INTEGRAL_MOULD, FORMAT_POINT_FRAME, EXPONENT_FRAME, STOP);
5380     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, INTEGRAL_MOULD, FORMAT_POINT_FRAME, STOP);
5381   }
5382   for (q = p; q != NO_NODE; FORWARD (q)) {
5383     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, FORMAT_POINT_FRAME, INTEGRAL_MOULD, EXPONENT_FRAME, STOP);
5384     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, FORMAT_POINT_FRAME, INTEGRAL_MOULD, STOP);
5385     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, FORMAT_POINT_FRAME, EXPONENT_FRAME, STOP);
5386     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, FORMAT_POINT_FRAME, STOP);
5387   }
5388   for (q = p; q != NO_NODE; FORWARD (q)) {
5389     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, INTEGRAL_MOULD, FORMAT_POINT_FRAME, INTEGRAL_MOULD, EXPONENT_FRAME, STOP);
5390     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, INTEGRAL_MOULD, FORMAT_POINT_FRAME, INTEGRAL_MOULD, STOP);
5391     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, INTEGRAL_MOULD, FORMAT_POINT_FRAME, EXPONENT_FRAME, STOP);
5392     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, INTEGRAL_MOULD, FORMAT_POINT_FRAME, STOP);
5393     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, FORMAT_POINT_FRAME, INTEGRAL_MOULD, EXPONENT_FRAME, STOP);
5394     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, FORMAT_POINT_FRAME, INTEGRAL_MOULD, STOP);
5395   }
5396   for (q = p; q != NO_NODE; FORWARD (q)) {
5397     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, SIGN_MOULD, INTEGRAL_MOULD, EXPONENT_FRAME, STOP);
5398     reduce (q, NO_NOTE, NO_TICK, REAL_PATTERN, INTEGRAL_MOULD, EXPONENT_FRAME, STOP);
5399   }
5400 /* Complex patterns */
5401   for (q = p; q != NO_NODE; FORWARD (q)) {
5402     reduce (q, NO_NOTE, NO_TICK, COMPLEX_PATTERN, REAL_PATTERN, FORMAT_I_FRAME, REAL_PATTERN, STOP);
5403   }
5404 /* Bits patterns */
5405   for (q = p; q != NO_NODE; FORWARD (q)) {
5406     reduce (q, NO_NOTE, NO_TICK, BITS_PATTERN, RADIX_FRAME, INTEGRAL_MOULD, STOP);
5407   }
5408 /* Integral patterns */
5409   for (q = p; q != NO_NODE; FORWARD (q)) {
5410     reduce (q, NO_NOTE, NO_TICK, INTEGRAL_PATTERN, SIGN_MOULD, INTEGRAL_MOULD, STOP);
5411     reduce (q, NO_NOTE, NO_TICK, INTEGRAL_PATTERN, INTEGRAL_MOULD, STOP);
5412   }
5413 /* Patterns */
5414   for (q = p; q != NO_NODE; FORWARD (q)) {
5415     reduce (q, NO_NOTE, NO_TICK, BOOLEAN_PATTERN, FORMAT_ITEM_B, COLLECTION, STOP);
5416     reduce (q, NO_NOTE, NO_TICK, CHOICE_PATTERN, FORMAT_ITEM_C, COLLECTION, STOP);
5417   }
5418   for (q = p; q != NO_NODE; FORWARD (q)) {
5419     reduce (q, NO_NOTE, NO_TICK, BOOLEAN_PATTERN, FORMAT_ITEM_B, STOP);
5420     reduce (q, NO_NOTE, NO_TICK, GENERAL_PATTERN, FORMAT_ITEM_G, STOP);
5421     reduce (q, NO_NOTE, NO_TICK, GENERAL_PATTERN, FORMAT_ITEM_H, STOP);
5422   }
5423   ambiguous_patterns (p);
5424   for (q = p; q != NO_NODE; FORWARD (q)) {
5425     reduce (q, a68_extension, NO_TICK, A68_PATTERN, BITS_C_PATTERN, STOP);
5426     reduce (q, a68_extension, NO_TICK, A68_PATTERN, CHAR_C_PATTERN, STOP);
5427     reduce (q, a68_extension, NO_TICK, A68_PATTERN, FIXED_C_PATTERN, STOP);
5428     reduce (q, a68_extension, NO_TICK, A68_PATTERN, FLOAT_C_PATTERN, STOP);
5429     reduce (q, a68_extension, NO_TICK, A68_PATTERN, GENERAL_C_PATTERN, STOP);
5430     reduce (q, a68_extension, NO_TICK, A68_PATTERN, INTEGRAL_C_PATTERN, STOP);
5431     reduce (q, a68_extension, NO_TICK, A68_PATTERN, STRING_C_PATTERN, STOP);
5432     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, BITS_PATTERN, STOP);
5433     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, BOOLEAN_PATTERN, STOP);
5434     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, CHOICE_PATTERN, STOP);
5435     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, COMPLEX_PATTERN, STOP);
5436     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, FORMAT_PATTERN, STOP);
5437     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, GENERAL_PATTERN, STOP);
5438     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, INTEGRAL_PATTERN, STOP);
5439     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, REAL_PATTERN, STOP);
5440     reduce (q, NO_NOTE, NO_TICK, A68_PATTERN, STRING_PATTERN, STOP);
5441   }
5442 /* Pictures */
5443   for (q = p; q != NO_NODE; FORWARD (q)) {
5444     reduce (q, NO_NOTE, NO_TICK, PICTURE, INSERTION, STOP);
5445     reduce (q, NO_NOTE, NO_TICK, PICTURE, A68_PATTERN, STOP);
5446     reduce (q, NO_NOTE, NO_TICK, PICTURE, COLLECTION, STOP);
5447     reduce (q, NO_NOTE, NO_TICK, PICTURE, REPLICATOR, COLLECTION, STOP);
5448   }
5449 /* Picture lists */
5450   for (q = p; q != NO_NODE; FORWARD (q)) {
5451     if (IS (q, PICTURE)) {
5452       BOOL_T siga = A68_TRUE;
5453       reduce (q, NO_NOTE, NO_TICK, PICTURE_LIST, PICTURE, STOP);
5454       while (siga) {
5455         siga = A68_FALSE;
5456         reduce (q, NO_NOTE, &siga, PICTURE_LIST, PICTURE_LIST, COMMA_SYMBOL, PICTURE, STOP);
5457         /* We filtered ambiguous patterns, so commas may be omitted */
5458         reduce (q, NO_NOTE, &siga, PICTURE_LIST, PICTURE_LIST, PICTURE, STOP);
5459       }
5460     }
5461   }
5462 }
5463 
5464 /**
5465 @brief Reduce secondaries completely.
5466 @param p Node in syntax tree.
5467 **/
5468 
5469 static void
reduce_secondaries(NODE_T * p)5470 reduce_secondaries (NODE_T * p)
5471 {
5472   NODE_T *q;
5473   BOOL_T siga;
5474   for (q = p; q != NO_NODE; FORWARD (q)) {
5475     reduce (q, NO_NOTE, NO_TICK, SECONDARY, PRIMARY, STOP);
5476     reduce (q, NO_NOTE, NO_TICK, GENERATOR, LOC_SYMBOL, DECLARER, STOP);
5477     reduce (q, NO_NOTE, NO_TICK, GENERATOR, HEAP_SYMBOL, DECLARER, STOP);
5478     reduce (q, NO_NOTE, NO_TICK, GENERATOR, NEW_SYMBOL, DECLARER, STOP);
5479     reduce (q, NO_NOTE, NO_TICK, SECONDARY, GENERATOR, STOP);
5480   }
5481   siga = A68_TRUE;
5482   while (siga) {
5483     siga = A68_FALSE;
5484     for (q = p; NEXT (q) != NO_NODE; FORWARD (q)) {
5485       ;
5486     }
5487     for (; q != NO_NODE; BACKWARD (q)) {
5488       reduce (q, NO_NOTE, &siga, SELECTION, SELECTOR, SECONDARY, STOP);
5489       reduce (q, NO_NOTE, &siga, SECONDARY, SELECTION, STOP);
5490     }
5491   }
5492 }
5493 
5494 /**
5495 @brief Whether "q" is an operator with priority "k".
5496 @param q Operator token.
5497 @param k Priority.
5498 @return Whether "q" is an operator with priority "k".
5499 **/
5500 
5501 static int
operator_with_priority(NODE_T * q,int k)5502 operator_with_priority (NODE_T * q, int k)
5503 {
5504   return (NEXT (q) != NO_NODE && ATTRIBUTE (NEXT (q)) == OPERATOR && PRIO (INFO (NEXT (q))) == k);
5505 }
5506 
5507 /**
5508 @brief Reduce formulae.
5509 @param p Node in syntax tree.
5510 **/
5511 
5512 static void
reduce_formulae(NODE_T * p)5513 reduce_formulae (NODE_T * p)
5514 {
5515   NODE_T *q = p;
5516   int priority;
5517   while (q != NO_NODE) {
5518     if (is_one_of (q, OPERATOR, SECONDARY, STOP)) {
5519       q = reduce_dyadic (q, STOP);
5520     } else {
5521       FORWARD (q);
5522     }
5523   }
5524 /* Reduce the expression */
5525   for (priority = MAX_PRIORITY; priority >= 0; priority--) {
5526     for (q = p; q != NO_NODE; FORWARD (q)) {
5527       if (operator_with_priority (q, priority)) {
5528         BOOL_T siga = A68_FALSE;
5529         NODE_T *op = NEXT (q);
5530         if (IS (q, SECONDARY)) {
5531           reduce (q, NO_NOTE, &siga, FORMULA, SECONDARY, OPERATOR, SECONDARY, STOP);
5532           reduce (q, NO_NOTE, &siga, FORMULA, SECONDARY, OPERATOR, MONADIC_FORMULA, STOP);
5533           reduce (q, NO_NOTE, &siga, FORMULA, SECONDARY, OPERATOR, FORMULA, STOP);
5534         } else if (IS (q, MONADIC_FORMULA)) {
5535           reduce (q, NO_NOTE, &siga, FORMULA, MONADIC_FORMULA, OPERATOR, SECONDARY, STOP);
5536           reduce (q, NO_NOTE, &siga, FORMULA, MONADIC_FORMULA, OPERATOR, MONADIC_FORMULA, STOP);
5537           reduce (q, NO_NOTE, &siga, FORMULA, MONADIC_FORMULA, OPERATOR, FORMULA, STOP);
5538         }
5539         if (priority == 0 && siga) {
5540           diagnostic_node (A68_SYNTAX_ERROR, op, ERROR_NO_PRIORITY);
5541         }
5542         siga = A68_TRUE;
5543         while (siga) {
5544           NODE_T *op2 = NEXT (q);
5545           siga = A68_FALSE;
5546           if (operator_with_priority (q, priority)) {
5547             reduce (q, NO_NOTE, &siga, FORMULA, FORMULA, OPERATOR, SECONDARY, STOP);
5548           }
5549           if (operator_with_priority (q, priority)) {
5550             reduce (q, NO_NOTE, &siga, FORMULA, FORMULA, OPERATOR, MONADIC_FORMULA, STOP);
5551           }
5552           if (operator_with_priority (q, priority)) {
5553             reduce (q, NO_NOTE, &siga, FORMULA, FORMULA, OPERATOR, FORMULA, STOP);
5554           }
5555           if (priority == 0 && siga) {
5556             diagnostic_node (A68_SYNTAX_ERROR, op2, ERROR_NO_PRIORITY);
5557           }
5558         }
5559       }
5560     }
5561   }
5562 }
5563 
5564 /**
5565 @brief Reduce dyadic expressions.
5566 @param p Node in syntax tree.
5567 @param u Current priority.
5568 @return Token from where to continue.
5569 **/
5570 
5571 static NODE_T *
reduce_dyadic(NODE_T * p,int u)5572 reduce_dyadic (NODE_T * p, int u)
5573 {
5574 /* We work inside out - higher priority expressions get reduced first */
5575   if (u > MAX_PRIORITY) {
5576     if (p == NO_NODE) {
5577       return (NO_NODE);
5578     } else if (IS (p, OPERATOR)) {
5579 /* Reduce monadic formulas */
5580       NODE_T *q = p;
5581       BOOL_T siga;
5582       do {
5583         PRIO (INFO (q)) = 10;
5584         siga = (BOOL_T) ((NEXT (q) != NO_NODE) && (IS (NEXT (q), OPERATOR)));
5585         if (siga) {
5586           FORWARD (q);
5587         }
5588       } while (siga);
5589       reduce (q, NO_NOTE, NO_TICK, MONADIC_FORMULA, OPERATOR, SECONDARY, STOP);
5590       while (q != p) {
5591         BACKWARD (q);
5592         reduce (q, NO_NOTE, NO_TICK, MONADIC_FORMULA, OPERATOR, MONADIC_FORMULA, STOP);
5593       }
5594     }
5595     FORWARD (p);
5596   } else {
5597     p = reduce_dyadic (p, u + 1);
5598     while (p != NO_NODE && IS (p, OPERATOR) && PRIO (INFO (p)) == u) {
5599       FORWARD (p);
5600       p = reduce_dyadic (p, u + 1);
5601     }
5602   }
5603   return (p);
5604 }
5605 
5606 /**
5607 @brief Reduce tertiaries completely.
5608 @param p Node in syntax tree.
5609 **/
5610 
5611 static void
reduce_tertiaries(NODE_T * p)5612 reduce_tertiaries (NODE_T * p)
5613 {
5614   NODE_T *q;
5615   BOOL_T siga;
5616   for (q = p; q != NO_NODE; FORWARD (q)) {
5617     reduce (q, NO_NOTE, NO_TICK, TERTIARY, NIHIL, STOP);
5618     reduce (q, NO_NOTE, NO_TICK, FORMULA, MONADIC_FORMULA, STOP);
5619     reduce (q, NO_NOTE, NO_TICK, TERTIARY, FORMULA, STOP);
5620     reduce (q, NO_NOTE, NO_TICK, TERTIARY, SECONDARY, STOP);
5621   }
5622   siga = A68_TRUE;
5623   while (siga) {
5624     siga = A68_FALSE;
5625     for (q = p; q != NO_NODE; FORWARD (q)) {
5626       reduce (q, NO_NOTE, &siga, TRANSPOSE_FUNCTION, TRANSPOSE_SYMBOL, TERTIARY, STOP);
5627       reduce (q, NO_NOTE, &siga, DIAGONAL_FUNCTION, TERTIARY, DIAGONAL_SYMBOL, TERTIARY, STOP);
5628       reduce (q, NO_NOTE, &siga, DIAGONAL_FUNCTION, DIAGONAL_SYMBOL, TERTIARY, STOP);
5629       reduce (q, NO_NOTE, &siga, COLUMN_FUNCTION, TERTIARY, COLUMN_SYMBOL, TERTIARY, STOP);
5630       reduce (q, NO_NOTE, &siga, COLUMN_FUNCTION, COLUMN_SYMBOL, TERTIARY, STOP);
5631       reduce (q, NO_NOTE, &siga, ROW_FUNCTION, TERTIARY, ROW_SYMBOL, TERTIARY, STOP);
5632       reduce (q, NO_NOTE, &siga, ROW_FUNCTION, ROW_SYMBOL, TERTIARY, STOP);
5633     }
5634     for (q = p; q != NO_NODE; FORWARD (q)) {
5635       reduce (q, a68_extension, &siga, TERTIARY, TRANSPOSE_FUNCTION, STOP);
5636       reduce (q, a68_extension, &siga, TERTIARY, DIAGONAL_FUNCTION, STOP);
5637       reduce (q, a68_extension, &siga, TERTIARY, COLUMN_FUNCTION, STOP);
5638       reduce (q, a68_extension, &siga, TERTIARY, ROW_FUNCTION, STOP);
5639     }
5640   }
5641   for (q = p; q != NO_NODE; FORWARD (q)) {
5642     reduce (q, NO_NOTE, NO_TICK, IDENTITY_RELATION, TERTIARY, IS_SYMBOL, TERTIARY, STOP);
5643     reduce (q, NO_NOTE, NO_TICK, IDENTITY_RELATION, TERTIARY, ISNT_SYMBOL, TERTIARY, STOP);
5644   }
5645   for (q = p; q != NO_NODE; FORWARD (q)) {
5646     reduce (q, NO_NOTE, NO_TICK, AND_FUNCTION, TERTIARY, ANDF_SYMBOL, TERTIARY, STOP);
5647     reduce (q, NO_NOTE, NO_TICK, OR_FUNCTION, TERTIARY, ORF_SYMBOL, TERTIARY, STOP);
5648   }
5649 }
5650 
5651 /**
5652 @brief Reduce units.
5653 @param p Node in syntax tree.
5654 **/
5655 
5656 static void
reduce_units(NODE_T * p)5657 reduce_units (NODE_T * p)
5658 {
5659   NODE_T *q;
5660 /* Stray ~ is a SKIP */
5661   for (q = p; q != NO_NODE; FORWARD (q)) {
5662     if (IS (q, OPERATOR) && IS_LITERALLY (q, "~")) {
5663       ATTRIBUTE (q) = SKIP;
5664     }
5665   }
5666 /* Reduce units */
5667   for (q = p; q != NO_NODE; FORWARD (q)) {
5668     reduce (q, NO_NOTE, NO_TICK, UNIT, ASSIGNATION, STOP);
5669     reduce (q, NO_NOTE, NO_TICK, UNIT, IDENTITY_RELATION, STOP);
5670     reduce (q, a68_extension, NO_TICK, UNIT, AND_FUNCTION, STOP);
5671     reduce (q, a68_extension, NO_TICK, UNIT, OR_FUNCTION, STOP);
5672     reduce (q, NO_NOTE, NO_TICK, UNIT, ROUTINE_TEXT, STOP);
5673     reduce (q, NO_NOTE, NO_TICK, UNIT, JUMP, STOP);
5674     reduce (q, NO_NOTE, NO_TICK, UNIT, SKIP, STOP);
5675     reduce (q, NO_NOTE, NO_TICK, UNIT, TERTIARY, STOP);
5676     reduce (q, NO_NOTE, NO_TICK, UNIT, ASSERTION, STOP);
5677     reduce (q, NO_NOTE, NO_TICK, UNIT, CODE_CLAUSE, STOP);
5678   }
5679 }
5680 
5681 /**
5682 @brief Reduce_generic arguments.
5683 @param p Node in syntax tree.
5684 **/
5685 
5686 static void
reduce_generic_arguments(NODE_T * p)5687 reduce_generic_arguments (NODE_T * p)
5688 {
5689   NODE_T *q;
5690   BOOL_T siga;
5691   for (q = p; q != NO_NODE; FORWARD (q)) {
5692     if (IS (q, UNIT)) {
5693       reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, COLON_SYMBOL, UNIT, AT_SYMBOL, UNIT, STOP);
5694       reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, COLON_SYMBOL, UNIT, STOP);
5695       reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, COLON_SYMBOL, AT_SYMBOL, UNIT, STOP);
5696       reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, COLON_SYMBOL, STOP);
5697       reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, DOTDOT_SYMBOL, UNIT, AT_SYMBOL, UNIT, STOP);
5698       reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, DOTDOT_SYMBOL, UNIT, STOP);
5699       reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, DOTDOT_SYMBOL, AT_SYMBOL, UNIT, STOP);
5700       reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, DOTDOT_SYMBOL, STOP);
5701     } else if (IS (q, COLON_SYMBOL)) {
5702       reduce (q, NO_NOTE, NO_TICK, TRIMMER, COLON_SYMBOL, UNIT, AT_SYMBOL, UNIT, STOP);
5703       reduce (q, NO_NOTE, NO_TICK, TRIMMER, COLON_SYMBOL, UNIT, STOP);
5704       reduce (q, NO_NOTE, NO_TICK, TRIMMER, COLON_SYMBOL, AT_SYMBOL, UNIT, STOP);
5705       reduce (q, NO_NOTE, NO_TICK, TRIMMER, COLON_SYMBOL, STOP);
5706     } else if (IS (q, DOTDOT_SYMBOL)) {
5707       reduce (q, NO_NOTE, NO_TICK, TRIMMER, DOTDOT_SYMBOL, UNIT, AT_SYMBOL, UNIT, STOP);
5708       reduce (q, NO_NOTE, NO_TICK, TRIMMER, DOTDOT_SYMBOL, UNIT, STOP);
5709       reduce (q, NO_NOTE, NO_TICK, TRIMMER, DOTDOT_SYMBOL, AT_SYMBOL, UNIT, STOP);
5710       reduce (q, NO_NOTE, NO_TICK, TRIMMER, DOTDOT_SYMBOL, STOP);
5711     }
5712   }
5713   for (q = p; q != NO_NODE; FORWARD (q)) {
5714     reduce (q, NO_NOTE, NO_TICK, TRIMMER, UNIT, AT_SYMBOL, UNIT, STOP);
5715   }
5716   for (q = p; q != NO_NODE; FORWARD (q)) {
5717     reduce (q, NO_NOTE, NO_TICK, TRIMMER, AT_SYMBOL, UNIT, STOP);
5718   }
5719   for (q = p; q && NEXT (q); FORWARD (q)) {
5720     if (IS (q, COMMA_SYMBOL)) {
5721       if (!(ATTRIBUTE (NEXT (q)) == UNIT || ATTRIBUTE (NEXT (q)) == TRIMMER)) {
5722         pad_node (q, TRIMMER);
5723       }
5724     } else {
5725       if (IS (NEXT (q), COMMA_SYMBOL)) {
5726         if (ISNT (q, UNIT) && ISNT (q, TRIMMER)) {
5727           pad_node (q, TRIMMER);
5728         }
5729       }
5730     }
5731   }
5732   q = NEXT (p);
5733   ABEND (q == NO_NODE, "erroneous parser state", NO_TEXT);
5734   reduce (q, NO_NOTE, NO_TICK, GENERIC_ARGUMENT_LIST, UNIT, STOP);
5735   reduce (q, NO_NOTE, NO_TICK, GENERIC_ARGUMENT_LIST, TRIMMER, STOP);
5736   do {
5737     siga = A68_FALSE;
5738     reduce (q, NO_NOTE, &siga, GENERIC_ARGUMENT_LIST, GENERIC_ARGUMENT_LIST, COMMA_SYMBOL, UNIT, STOP);
5739     reduce (q, NO_NOTE, &siga, GENERIC_ARGUMENT_LIST, GENERIC_ARGUMENT_LIST, COMMA_SYMBOL, TRIMMER, STOP);
5740     reduce (q, strange_separator, &siga, GENERIC_ARGUMENT_LIST, GENERIC_ARGUMENT_LIST, UNIT, STOP);
5741     reduce (q, strange_separator, &siga, GENERIC_ARGUMENT_LIST, GENERIC_ARGUMENT_LIST, TRIMMER, STOP);
5742   } while (siga);
5743 }
5744 
5745 /**
5746 @brief Reduce bounds.
5747 @param p Node in syntax tree.
5748 **/
5749 
5750 static void
reduce_bounds(NODE_T * p)5751 reduce_bounds (NODE_T * p)
5752 {
5753   NODE_T *q;
5754   BOOL_T siga;
5755   for (q = p; q != NO_NODE; FORWARD (q)) {
5756     reduce (q, NO_NOTE, NO_TICK, BOUND, UNIT, COLON_SYMBOL, UNIT, STOP);
5757     reduce (q, NO_NOTE, NO_TICK, BOUND, UNIT, DOTDOT_SYMBOL, UNIT, STOP);
5758     reduce (q, NO_NOTE, NO_TICK, BOUND, UNIT, STOP);
5759   }
5760   q = NEXT (p);
5761   reduce (q, NO_NOTE, NO_TICK, BOUNDS_LIST, BOUND, STOP);
5762   reduce (q, NO_NOTE, NO_TICK, FORMAL_BOUNDS_LIST, COMMA_SYMBOL, STOP);
5763   reduce (q, NO_NOTE, NO_TICK, ALT_FORMAL_BOUNDS_LIST, COLON_SYMBOL, STOP);
5764   reduce (q, NO_NOTE, NO_TICK, ALT_FORMAL_BOUNDS_LIST, DOTDOT_SYMBOL, STOP);
5765   do {
5766     siga = A68_FALSE;
5767     reduce (q, NO_NOTE, &siga, BOUNDS_LIST, BOUNDS_LIST, COMMA_SYMBOL, BOUND, STOP);
5768     reduce (q, NO_NOTE, &siga, FORMAL_BOUNDS_LIST, FORMAL_BOUNDS_LIST, COMMA_SYMBOL, STOP);
5769     reduce (q, NO_NOTE, &siga, ALT_FORMAL_BOUNDS_LIST, FORMAL_BOUNDS_LIST, COLON_SYMBOL, STOP);
5770     reduce (q, NO_NOTE, &siga, ALT_FORMAL_BOUNDS_LIST, FORMAL_BOUNDS_LIST, DOTDOT_SYMBOL, STOP);
5771     reduce (q, NO_NOTE, &siga, FORMAL_BOUNDS_LIST, ALT_FORMAL_BOUNDS_LIST, COMMA_SYMBOL, STOP);
5772     reduce (q, strange_separator, &siga, BOUNDS_LIST, BOUNDS_LIST, BOUND, STOP);
5773   } while (siga);
5774 }
5775 
5776 /**
5777 @brief Reduce argument packs.
5778 @param p Node in syntax tree.
5779 **/
5780 
5781 static void
reduce_arguments(NODE_T * p)5782 reduce_arguments (NODE_T * p)
5783 {
5784   if (NEXT (p) != NO_NODE) {
5785     NODE_T *q = NEXT (p);
5786     BOOL_T siga;
5787     reduce (q, NO_NOTE, NO_TICK, ARGUMENT_LIST, UNIT, STOP);
5788     do {
5789       siga = A68_FALSE;
5790       reduce (q, NO_NOTE, &siga, ARGUMENT_LIST, ARGUMENT_LIST, COMMA_SYMBOL, UNIT, STOP);
5791       reduce (q, strange_separator, &siga, ARGUMENT_LIST, ARGUMENT_LIST, UNIT, STOP);
5792     } while (siga);
5793   }
5794 }
5795 
5796 /**
5797 @brief Reduce declarations.
5798 @param p Node in syntax tree.
5799 **/
5800 
5801 static void
reduce_basic_declarations(NODE_T * p)5802 reduce_basic_declarations (NODE_T * p)
5803 {
5804   NODE_T *q;
5805   for (q = p; q != NO_NODE; FORWARD (q)) {
5806     reduce (q, NO_NOTE, NO_TICK, ENVIRON_NAME, ENVIRON_SYMBOL, ROW_CHAR_DENOTATION, STOP);
5807     reduce (q, NO_NOTE, NO_TICK, PRIORITY_DECLARATION, PRIO_SYMBOL, DEFINING_OPERATOR, EQUALS_SYMBOL, PRIORITY, STOP);
5808     reduce (q, NO_NOTE, NO_TICK, MODE_DECLARATION, MODE_SYMBOL, DEFINING_INDICANT, EQUALS_SYMBOL, DECLARER, STOP);
5809     reduce (q, NO_NOTE, NO_TICK, MODE_DECLARATION, MODE_SYMBOL, DEFINING_INDICANT, EQUALS_SYMBOL, VOID_SYMBOL, STOP);
5810     reduce (q, NO_NOTE, NO_TICK, PROCEDURE_DECLARATION, PROC_SYMBOL, DEFINING_IDENTIFIER, EQUALS_SYMBOL, ROUTINE_TEXT, STOP);
5811     reduce (q, NO_NOTE, NO_TICK, PROCEDURE_VARIABLE_DECLARATION, PROC_SYMBOL, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, ROUTINE_TEXT, STOP);
5812     reduce (q, NO_NOTE, NO_TICK, PROCEDURE_VARIABLE_DECLARATION, QUALIFIER, PROC_SYMBOL, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, ROUTINE_TEXT, STOP);
5813     reduce (q, NO_NOTE, NO_TICK, BRIEF_OPERATOR_DECLARATION, OP_SYMBOL, DEFINING_OPERATOR, EQUALS_SYMBOL, ROUTINE_TEXT, STOP);
5814 /* Errors */
5815     reduce (q, strange_tokens, NO_TICK, PRIORITY_DECLARATION, PRIO_SYMBOL, -DEFINING_OPERATOR, -EQUALS_SYMBOL, -PRIORITY, STOP);
5816     reduce (q, strange_tokens, NO_TICK, MODE_DECLARATION, MODE_SYMBOL, DEFINING_INDICANT, EQUALS_SYMBOL, -DECLARER, STOP);
5817     reduce (q, strange_tokens, NO_TICK, PROCEDURE_DECLARATION, PROC_SYMBOL, DEFINING_IDENTIFIER, EQUALS_SYMBOL, -ROUTINE_TEXT, STOP);
5818     reduce (q, strange_tokens, NO_TICK, PROCEDURE_VARIABLE_DECLARATION, PROC_SYMBOL, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, -ROUTINE_TEXT, STOP);
5819     reduce (q, strange_tokens, NO_TICK, PROCEDURE_VARIABLE_DECLARATION, QUALIFIER, PROC_SYMBOL, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, -ROUTINE_TEXT, STOP);
5820     reduce (q, strange_tokens, NO_TICK, BRIEF_OPERATOR_DECLARATION, OP_SYMBOL, DEFINING_OPERATOR, EQUALS_SYMBOL, -ROUTINE_TEXT, STOP);
5821 /* Errors. WILDCARD catches TERTIARY which catches IDENTIFIER */
5822     reduce (q, strange_tokens, NO_TICK, PROCEDURE_DECLARATION, PROC_SYMBOL, WILDCARD, ROUTINE_TEXT, STOP);
5823   }
5824   for (q = p; q != NO_NODE; FORWARD (q)) {
5825     BOOL_T siga;
5826     do {
5827       siga = A68_FALSE;
5828       reduce (q, NO_NOTE, &siga, ENVIRON_NAME, ENVIRON_NAME, COMMA_SYMBOL, ROW_CHAR_DENOTATION, STOP);
5829       reduce (q, NO_NOTE, &siga, PRIORITY_DECLARATION, PRIORITY_DECLARATION, COMMA_SYMBOL, DEFINING_OPERATOR, EQUALS_SYMBOL, PRIORITY, STOP);
5830       reduce (q, NO_NOTE, &siga, MODE_DECLARATION, MODE_DECLARATION, COMMA_SYMBOL, DEFINING_INDICANT, EQUALS_SYMBOL, DECLARER, STOP);
5831       reduce (q, NO_NOTE, &siga, MODE_DECLARATION, MODE_DECLARATION, COMMA_SYMBOL, DEFINING_INDICANT, EQUALS_SYMBOL, VOID_SYMBOL, STOP);
5832       reduce (q, NO_NOTE, &siga, PROCEDURE_DECLARATION, PROCEDURE_DECLARATION, COMMA_SYMBOL, DEFINING_IDENTIFIER, EQUALS_SYMBOL, ROUTINE_TEXT, STOP);
5833       reduce (q, NO_NOTE, &siga, PROCEDURE_VARIABLE_DECLARATION, PROCEDURE_VARIABLE_DECLARATION, COMMA_SYMBOL, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, ROUTINE_TEXT, STOP);
5834       reduce (q, NO_NOTE, &siga, BRIEF_OPERATOR_DECLARATION, BRIEF_OPERATOR_DECLARATION, COMMA_SYMBOL, DEFINING_OPERATOR, EQUALS_SYMBOL, ROUTINE_TEXT, STOP);
5835 /* Errors. WILDCARD catches TERTIARY which catches IDENTIFIER */
5836       reduce (q, strange_tokens, &siga, PROCEDURE_DECLARATION, PROCEDURE_DECLARATION, COMMA_SYMBOL, WILDCARD, ROUTINE_TEXT, STOP);
5837     } while (siga);
5838   }
5839 }
5840 
5841 /**
5842 @brief Reduce declaration lists.
5843 @param p Node in syntax tree.
5844 **/
5845 
5846 static void
reduce_declaration_lists(NODE_T * p)5847 reduce_declaration_lists (NODE_T * p)
5848 {
5849   NODE_T *q;
5850   for (q = p; q != NO_NODE; FORWARD (q)) {
5851     reduce (q, NO_NOTE, NO_TICK, IDENTITY_DECLARATION, DECLARER, DEFINING_IDENTIFIER, EQUALS_SYMBOL, UNIT, STOP);
5852     reduce (q, NO_NOTE, NO_TICK, VARIABLE_DECLARATION, QUALIFIER, DECLARER, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, UNIT, STOP);
5853     reduce (q, NO_NOTE, NO_TICK, VARIABLE_DECLARATION, QUALIFIER, DECLARER, DEFINING_IDENTIFIER, STOP);
5854     reduce (q, NO_NOTE, NO_TICK, VARIABLE_DECLARATION, DECLARER, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, UNIT, STOP);
5855     reduce (q, NO_NOTE, NO_TICK, VARIABLE_DECLARATION, DECLARER, DEFINING_IDENTIFIER, STOP);
5856   }
5857   for (q = p; q != NO_NODE; FORWARD (q)) {
5858     BOOL_T siga;
5859     do {
5860       siga = A68_FALSE;
5861       reduce (q, NO_NOTE, &siga, IDENTITY_DECLARATION, IDENTITY_DECLARATION, COMMA_SYMBOL, DEFINING_IDENTIFIER, EQUALS_SYMBOL, UNIT, STOP);
5862       reduce (q, NO_NOTE, &siga, VARIABLE_DECLARATION, VARIABLE_DECLARATION, COMMA_SYMBOL, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, UNIT, STOP);
5863       if (!whether (q, VARIABLE_DECLARATION, COMMA_SYMBOL, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, UNIT, STOP)) {
5864         reduce (q, NO_NOTE, &siga, VARIABLE_DECLARATION, VARIABLE_DECLARATION, COMMA_SYMBOL, DEFINING_IDENTIFIER, STOP);
5865       }
5866     } while (siga);
5867   }
5868   for (q = p; q != NO_NODE; FORWARD (q)) {
5869     reduce (q, NO_NOTE, NO_TICK, OPERATOR_DECLARATION, OPERATOR_PLAN, DEFINING_OPERATOR, EQUALS_SYMBOL, UNIT, STOP);
5870   }
5871   for (q = p; q != NO_NODE; FORWARD (q)) {
5872     BOOL_T siga;
5873     do {
5874       siga = A68_FALSE;
5875       reduce (q, NO_NOTE, &siga, OPERATOR_DECLARATION, OPERATOR_DECLARATION, COMMA_SYMBOL, DEFINING_OPERATOR, EQUALS_SYMBOL, UNIT, STOP);
5876     } while (siga);
5877   }
5878   for (q = p; q != NO_NODE; FORWARD (q)) {
5879     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, MODE_DECLARATION, STOP);
5880     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, PRIORITY_DECLARATION, STOP);
5881     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, BRIEF_OPERATOR_DECLARATION, STOP);
5882     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, OPERATOR_DECLARATION, STOP);
5883     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, IDENTITY_DECLARATION, STOP);
5884     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, PROCEDURE_DECLARATION, STOP);
5885     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, PROCEDURE_VARIABLE_DECLARATION, STOP);
5886     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, VARIABLE_DECLARATION, STOP);
5887     reduce (q, NO_NOTE, NO_TICK, DECLARATION_LIST, ENVIRON_NAME, STOP);
5888   }
5889   for (q = p; q != NO_NODE; FORWARD (q)) {
5890     BOOL_T siga;
5891     do {
5892       siga = A68_FALSE;
5893       reduce (q, NO_NOTE, &siga, DECLARATION_LIST, DECLARATION_LIST, COMMA_SYMBOL, DECLARATION_LIST, STOP);
5894     } while (siga);
5895   }
5896 }
5897 
5898 /**
5899 @brief Reduce serial clauses.
5900 @param p Node in syntax tree.
5901 **/
5902 
5903 static void
reduce_serial_clauses(NODE_T * p)5904 reduce_serial_clauses (NODE_T * p)
5905 {
5906   if (NEXT (p) != NO_NODE) {
5907     NODE_T *q = NEXT (p), *u;
5908     BOOL_T siga, label_seen;
5909 /* Check wrong exits */
5910     for (u = q; u != NO_NODE; FORWARD (u)) {
5911       if (IS (u, EXIT_SYMBOL)) {
5912         if (NEXT (u) == NO_NODE || ISNT (NEXT (u), LABELED_UNIT)) {
5913           diagnostic_node (A68_SYNTAX_ERROR, u, ERROR_LABELED_UNIT_MUST_FOLLOW);
5914         }
5915       }
5916     }
5917 /* Check wrong jumps and declarations */
5918     for (u = q, label_seen = A68_FALSE; u != NO_NODE; FORWARD (u)) {
5919       if (IS (u, LABELED_UNIT)) {
5920         label_seen = A68_TRUE;
5921       } else if (IS (u, DECLARATION_LIST)) {
5922         if (label_seen) {
5923           diagnostic_node (A68_SYNTAX_ERROR, u, ERROR_LABEL_BEFORE_DECLARATION);
5924         }
5925       }
5926     }
5927 /* Reduce serial clauses */
5928     reduce (q, NO_NOTE, NO_TICK, SERIAL_CLAUSE, LABELED_UNIT, STOP);
5929     reduce (q, NO_NOTE, NO_TICK, SERIAL_CLAUSE, UNIT, STOP);
5930     reduce (q, NO_NOTE, NO_TICK, INITIALISER_SERIES, DECLARATION_LIST, STOP);
5931     do {
5932       siga = A68_FALSE;
5933       if (IS (q, SERIAL_CLAUSE)) {
5934         reduce (q, NO_NOTE, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, SEMI_SYMBOL, UNIT, STOP);
5935         reduce (q, NO_NOTE, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, EXIT_SYMBOL, LABELED_UNIT, STOP);
5936         reduce (q, NO_NOTE, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, SEMI_SYMBOL, LABELED_UNIT, STOP);
5937         reduce (q, NO_NOTE, &siga, INITIALISER_SERIES, SERIAL_CLAUSE, SEMI_SYMBOL, DECLARATION_LIST, STOP);
5938         /* Errors */
5939         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, COMMA_SYMBOL, UNIT, STOP);
5940         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, COMMA_SYMBOL, LABELED_UNIT, STOP);
5941         reduce (q, strange_separator, &siga, INITIALISER_SERIES, SERIAL_CLAUSE, COMMA_SYMBOL, DECLARATION_LIST, STOP);
5942         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, COLON_SYMBOL, UNIT, STOP);
5943         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, COLON_SYMBOL, LABELED_UNIT, STOP);
5944         reduce (q, strange_separator, &siga, INITIALISER_SERIES, SERIAL_CLAUSE, COLON_SYMBOL, DECLARATION_LIST, STOP);
5945         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, UNIT, STOP);
5946         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, SERIAL_CLAUSE, LABELED_UNIT, STOP);
5947         reduce (q, strange_separator, &siga, INITIALISER_SERIES, SERIAL_CLAUSE, DECLARATION_LIST, STOP);
5948       } else if (IS (q, INITIALISER_SERIES)) {
5949         reduce (q, NO_NOTE, &siga, SERIAL_CLAUSE, INITIALISER_SERIES, SEMI_SYMBOL, UNIT, STOP);
5950         reduce (q, NO_NOTE, &siga, SERIAL_CLAUSE, INITIALISER_SERIES, SEMI_SYMBOL, LABELED_UNIT, STOP);
5951         reduce (q, NO_NOTE, &siga, INITIALISER_SERIES, INITIALISER_SERIES, SEMI_SYMBOL, DECLARATION_LIST, STOP);
5952         /* Errors */
5953         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, INITIALISER_SERIES, COMMA_SYMBOL, UNIT, STOP);
5954         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, INITIALISER_SERIES, COMMA_SYMBOL, LABELED_UNIT, STOP);
5955         reduce (q, strange_separator, &siga, INITIALISER_SERIES, INITIALISER_SERIES, COMMA_SYMBOL, DECLARATION_LIST, STOP);
5956         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, INITIALISER_SERIES, COLON_SYMBOL, UNIT, STOP);
5957         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, INITIALISER_SERIES, COLON_SYMBOL, LABELED_UNIT, STOP);
5958         reduce (q, strange_separator, &siga, INITIALISER_SERIES, INITIALISER_SERIES, COLON_SYMBOL, DECLARATION_LIST, STOP);
5959         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, INITIALISER_SERIES, UNIT, STOP);
5960         reduce (q, strange_separator, &siga, SERIAL_CLAUSE, INITIALISER_SERIES, LABELED_UNIT, STOP);
5961         reduce (q, strange_separator, &siga, INITIALISER_SERIES, INITIALISER_SERIES, DECLARATION_LIST, STOP);
5962       }
5963     }
5964     while (siga);
5965   }
5966 }
5967 
5968 /**
5969 @brief Reduce enquiry clauses.
5970 @param p Node in syntax tree.
5971 **/
5972 
5973 static void
reduce_enquiry_clauses(NODE_T * p)5974 reduce_enquiry_clauses (NODE_T * p)
5975 {
5976   if (NEXT (p) != NO_NODE) {
5977     NODE_T *q = NEXT (p);
5978     BOOL_T siga;
5979     reduce (q, NO_NOTE, NO_TICK, ENQUIRY_CLAUSE, UNIT, STOP);
5980     reduce (q, NO_NOTE, NO_TICK, INITIALISER_SERIES, DECLARATION_LIST, STOP);
5981     do {
5982       siga = A68_FALSE;
5983       if (IS (q, ENQUIRY_CLAUSE)) {
5984         reduce (q, NO_NOTE, &siga, ENQUIRY_CLAUSE, ENQUIRY_CLAUSE, SEMI_SYMBOL, UNIT, STOP);
5985         reduce (q, NO_NOTE, &siga, INITIALISER_SERIES, ENQUIRY_CLAUSE, SEMI_SYMBOL, DECLARATION_LIST, STOP);
5986         reduce (q, strange_separator, &siga, ENQUIRY_CLAUSE, ENQUIRY_CLAUSE, COMMA_SYMBOL, UNIT, STOP);
5987         reduce (q, strange_separator, &siga, INITIALISER_SERIES, ENQUIRY_CLAUSE, COMMA_SYMBOL, DECLARATION_LIST, STOP);
5988         reduce (q, strange_separator, &siga, ENQUIRY_CLAUSE, ENQUIRY_CLAUSE, COLON_SYMBOL, UNIT, STOP);
5989         reduce (q, strange_separator, &siga, INITIALISER_SERIES, ENQUIRY_CLAUSE, COLON_SYMBOL, DECLARATION_LIST, STOP);
5990         reduce (q, strange_separator, &siga, ENQUIRY_CLAUSE, ENQUIRY_CLAUSE, UNIT, STOP);
5991         reduce (q, strange_separator, &siga, INITIALISER_SERIES, ENQUIRY_CLAUSE, DECLARATION_LIST, STOP);
5992       } else if (IS (q, INITIALISER_SERIES)) {
5993         reduce (q, NO_NOTE, &siga, ENQUIRY_CLAUSE, INITIALISER_SERIES, SEMI_SYMBOL, UNIT, STOP);
5994         reduce (q, NO_NOTE, &siga, INITIALISER_SERIES, INITIALISER_SERIES, SEMI_SYMBOL, DECLARATION_LIST, STOP);
5995         reduce (q, strange_separator, &siga, ENQUIRY_CLAUSE, INITIALISER_SERIES, COMMA_SYMBOL, UNIT, STOP);
5996         reduce (q, strange_separator, &siga, INITIALISER_SERIES, INITIALISER_SERIES, COMMA_SYMBOL, DECLARATION_LIST, STOP);
5997         reduce (q, strange_separator, &siga, ENQUIRY_CLAUSE, INITIALISER_SERIES, COLON_SYMBOL, UNIT, STOP);
5998         reduce (q, strange_separator, &siga, INITIALISER_SERIES, INITIALISER_SERIES, COLON_SYMBOL, DECLARATION_LIST, STOP);
5999         reduce (q, strange_separator, &siga, ENQUIRY_CLAUSE, INITIALISER_SERIES, UNIT, STOP);
6000         reduce (q, strange_separator, &siga, INITIALISER_SERIES, INITIALISER_SERIES, DECLARATION_LIST, STOP);
6001       }
6002     }
6003     while (siga);
6004   }
6005 }
6006 
6007 /**
6008 @brief Reduce collateral clauses.
6009 @param p Node in syntax tree.
6010 **/
6011 
6012 static void
reduce_collateral_clauses(NODE_T * p)6013 reduce_collateral_clauses (NODE_T * p)
6014 {
6015   if (NEXT (p) != NO_NODE) {
6016     NODE_T *q = NEXT (p);
6017     if (IS (q, UNIT)) {
6018       BOOL_T siga;
6019       reduce (q, NO_NOTE, NO_TICK, UNIT_LIST, UNIT, STOP);
6020       do {
6021         siga = A68_FALSE;
6022         reduce (q, NO_NOTE, &siga, UNIT_LIST, UNIT_LIST, COMMA_SYMBOL, UNIT, STOP);
6023         reduce (q, strange_separator, &siga, UNIT_LIST, UNIT_LIST, UNIT, STOP);
6024       } while (siga);
6025     } else if (IS (q, SPECIFIED_UNIT)) {
6026       BOOL_T siga;
6027       reduce (q, NO_NOTE, NO_TICK, SPECIFIED_UNIT_LIST, SPECIFIED_UNIT, STOP);
6028       do {
6029         siga = A68_FALSE;
6030         reduce (q, NO_NOTE, &siga, SPECIFIED_UNIT_LIST, SPECIFIED_UNIT_LIST, COMMA_SYMBOL, SPECIFIED_UNIT, STOP);
6031         reduce (q, strange_separator, &siga, SPECIFIED_UNIT_LIST, SPECIFIED_UNIT_LIST, SPECIFIED_UNIT, STOP);
6032       } while (siga);
6033     }
6034   }
6035 }
6036 
6037 /**
6038 @brief Reduces enclosed clauses.
6039 @param q Node in syntax tree.
6040 @param expect Information the parser may have on what is expected.
6041 **/
6042 
6043 static void
reduce_enclosed_clauses(NODE_T * q,int expect)6044 reduce_enclosed_clauses (NODE_T * q, int expect)
6045 {
6046   NODE_T *p = q;
6047   if (SUB (p) == NO_NODE) {
6048     if (IS (p, FOR_SYMBOL)) {
6049       reduce (p, NO_NOTE, NO_TICK, FOR_PART, FOR_SYMBOL, DEFINING_IDENTIFIER, STOP);
6050     } else if (IS (p, OPEN_SYMBOL)) {
6051       if (expect == ENQUIRY_CLAUSE) {
6052         reduce (p, NO_NOTE, NO_TICK, OPEN_PART, OPEN_SYMBOL, ENQUIRY_CLAUSE, STOP);
6053       } else if (expect == ARGUMENT) {
6054         reduce (p, NO_NOTE, NO_TICK, ARGUMENT, OPEN_SYMBOL, CLOSE_SYMBOL, STOP);
6055         reduce (p, NO_NOTE, NO_TICK, ARGUMENT, OPEN_SYMBOL, ARGUMENT_LIST, CLOSE_SYMBOL, STOP);
6056         reduce (p, empty_clause, NO_TICK, ARGUMENT, OPEN_SYMBOL, INITIALISER_SERIES, CLOSE_SYMBOL, STOP);
6057       } else if (expect == GENERIC_ARGUMENT) {
6058         if (whether (p, OPEN_SYMBOL, CLOSE_SYMBOL, STOP)) {
6059           pad_node (p, TRIMMER);
6060           reduce (p, NO_NOTE, NO_TICK, GENERIC_ARGUMENT, OPEN_SYMBOL, TRIMMER, CLOSE_SYMBOL, STOP);
6061         }
6062         reduce (p, NO_NOTE, NO_TICK, GENERIC_ARGUMENT, OPEN_SYMBOL, GENERIC_ARGUMENT_LIST, CLOSE_SYMBOL, STOP);
6063       } else if (expect == BOUNDS) {
6064         reduce (p, NO_NOTE, NO_TICK, FORMAL_BOUNDS, OPEN_SYMBOL, CLOSE_SYMBOL, STOP);
6065         reduce (p, NO_NOTE, NO_TICK, BOUNDS, OPEN_SYMBOL, BOUNDS_LIST, CLOSE_SYMBOL, STOP);
6066         reduce (p, NO_NOTE, NO_TICK, FORMAL_BOUNDS, OPEN_SYMBOL, FORMAL_BOUNDS_LIST, CLOSE_SYMBOL, STOP);
6067         reduce (p, NO_NOTE, NO_TICK, FORMAL_BOUNDS, OPEN_SYMBOL, ALT_FORMAL_BOUNDS_LIST, CLOSE_SYMBOL, STOP);
6068       } else {
6069         reduce (p, NO_NOTE, NO_TICK, CLOSED_CLAUSE, OPEN_SYMBOL, SERIAL_CLAUSE, CLOSE_SYMBOL, STOP);
6070         reduce (p, NO_NOTE, NO_TICK, COLLATERAL_CLAUSE, OPEN_SYMBOL, UNIT_LIST, CLOSE_SYMBOL, STOP);
6071         reduce (p, NO_NOTE, NO_TICK, COLLATERAL_CLAUSE, OPEN_SYMBOL, CLOSE_SYMBOL, STOP);
6072         reduce (p, empty_clause, NO_TICK, CLOSED_CLAUSE, OPEN_SYMBOL, INITIALISER_SERIES, CLOSE_SYMBOL, STOP);
6073       }
6074     } else if (IS (p, SUB_SYMBOL)) {
6075       if (expect == GENERIC_ARGUMENT) {
6076         if (whether (p, SUB_SYMBOL, BUS_SYMBOL, STOP)) {
6077           pad_node (p, TRIMMER);
6078           reduce (p, NO_NOTE, NO_TICK, GENERIC_ARGUMENT, SUB_SYMBOL, TRIMMER, BUS_SYMBOL, STOP);
6079         }
6080         reduce (p, NO_NOTE, NO_TICK, GENERIC_ARGUMENT, SUB_SYMBOL, GENERIC_ARGUMENT_LIST, BUS_SYMBOL, STOP);
6081       } else if (expect == BOUNDS) {
6082         reduce (p, NO_NOTE, NO_TICK, FORMAL_BOUNDS, SUB_SYMBOL, BUS_SYMBOL, STOP);
6083         reduce (p, NO_NOTE, NO_TICK, BOUNDS, SUB_SYMBOL, BOUNDS_LIST, BUS_SYMBOL, STOP);
6084         reduce (p, NO_NOTE, NO_TICK, FORMAL_BOUNDS, SUB_SYMBOL, FORMAL_BOUNDS_LIST, BUS_SYMBOL, STOP);
6085         reduce (p, NO_NOTE, NO_TICK, FORMAL_BOUNDS, SUB_SYMBOL, ALT_FORMAL_BOUNDS_LIST, BUS_SYMBOL, STOP);
6086       }
6087     } else if (IS (p, BEGIN_SYMBOL)) {
6088       reduce (p, NO_NOTE, NO_TICK, COLLATERAL_CLAUSE, BEGIN_SYMBOL, UNIT_LIST, END_SYMBOL, STOP);
6089       reduce (p, NO_NOTE, NO_TICK, COLLATERAL_CLAUSE, BEGIN_SYMBOL, END_SYMBOL, STOP);
6090       reduce (p, NO_NOTE, NO_TICK, CLOSED_CLAUSE, BEGIN_SYMBOL, SERIAL_CLAUSE, END_SYMBOL, STOP);
6091       reduce (p, empty_clause, NO_TICK, CLOSED_CLAUSE, BEGIN_SYMBOL, INITIALISER_SERIES, END_SYMBOL, STOP);
6092     } else if (IS (p, FORMAT_DELIMITER_SYMBOL)) {
6093       reduce (p, NO_NOTE, NO_TICK, FORMAT_TEXT, FORMAT_DELIMITER_SYMBOL, PICTURE_LIST, FORMAT_DELIMITER_SYMBOL, STOP);
6094       reduce (p, NO_NOTE, NO_TICK, FORMAT_TEXT, FORMAT_DELIMITER_SYMBOL, FORMAT_DELIMITER_SYMBOL, STOP);
6095     } else if (IS (p, FORMAT_OPEN_SYMBOL)) {
6096       reduce (p, NO_NOTE, NO_TICK, COLLECTION, FORMAT_OPEN_SYMBOL, PICTURE_LIST, FORMAT_CLOSE_SYMBOL, STOP);
6097     } else if (IS (p, IF_SYMBOL)) {
6098       reduce (p, NO_NOTE, NO_TICK, IF_PART, IF_SYMBOL, ENQUIRY_CLAUSE, STOP);
6099       reduce (p, empty_clause, NO_TICK, IF_PART, IF_SYMBOL, INITIALISER_SERIES, STOP);
6100     } else if (IS (p, THEN_SYMBOL)) {
6101       reduce (p, NO_NOTE, NO_TICK, THEN_PART, THEN_SYMBOL, SERIAL_CLAUSE, STOP);
6102       reduce (p, empty_clause, NO_TICK, THEN_PART, THEN_SYMBOL, INITIALISER_SERIES, STOP);
6103     } else if (IS (p, ELSE_SYMBOL)) {
6104       reduce (p, NO_NOTE, NO_TICK, ELSE_PART, ELSE_SYMBOL, SERIAL_CLAUSE, STOP);
6105       reduce (p, empty_clause, NO_TICK, ELSE_PART, ELSE_SYMBOL, INITIALISER_SERIES, STOP);
6106     } else if (IS (p, ELIF_SYMBOL)) {
6107       reduce (p, NO_NOTE, NO_TICK, ELIF_IF_PART, ELIF_SYMBOL, ENQUIRY_CLAUSE, STOP);
6108     } else if (IS (p, CASE_SYMBOL)) {
6109       reduce (p, NO_NOTE, NO_TICK, CASE_PART, CASE_SYMBOL, ENQUIRY_CLAUSE, STOP);
6110       reduce (p, empty_clause, NO_TICK, CASE_PART, CASE_SYMBOL, INITIALISER_SERIES, STOP);
6111     } else if (IS (p, IN_SYMBOL)) {
6112       reduce (p, NO_NOTE, NO_TICK, CASE_IN_PART, IN_SYMBOL, UNIT_LIST, STOP);
6113       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_IN_PART, IN_SYMBOL, SPECIFIED_UNIT_LIST, STOP);
6114     } else if (IS (p, OUT_SYMBOL)) {
6115       reduce (p, NO_NOTE, NO_TICK, OUT_PART, OUT_SYMBOL, SERIAL_CLAUSE, STOP);
6116       reduce (p, empty_clause, NO_TICK, OUT_PART, OUT_SYMBOL, INITIALISER_SERIES, STOP);
6117     } else if (IS (p, OUSE_SYMBOL)) {
6118       reduce (p, NO_NOTE, NO_TICK, OUSE_PART, OUSE_SYMBOL, ENQUIRY_CLAUSE, STOP);
6119     } else if (IS (p, THEN_BAR_SYMBOL)) {
6120       reduce (p, NO_NOTE, NO_TICK, CHOICE, THEN_BAR_SYMBOL, SERIAL_CLAUSE, STOP);
6121       reduce (p, NO_NOTE, NO_TICK, CASE_CHOICE_CLAUSE, THEN_BAR_SYMBOL, UNIT_LIST, STOP);
6122       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_CHOICE, THEN_BAR_SYMBOL, SPECIFIED_UNIT_LIST, STOP);
6123       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_CHOICE, THEN_BAR_SYMBOL, SPECIFIED_UNIT, STOP);
6124       reduce (p, empty_clause, NO_TICK, CHOICE, THEN_BAR_SYMBOL, INITIALISER_SERIES, STOP);
6125     } else if (IS (p, ELSE_BAR_SYMBOL)) {
6126       reduce (p, NO_NOTE, NO_TICK, ELSE_OPEN_PART, ELSE_BAR_SYMBOL, ENQUIRY_CLAUSE, STOP);
6127       reduce (p, empty_clause, NO_TICK, ELSE_OPEN_PART, ELSE_BAR_SYMBOL, INITIALISER_SERIES, STOP);
6128     } else if (IS (p, FROM_SYMBOL)) {
6129       reduce (p, NO_NOTE, NO_TICK, FROM_PART, FROM_SYMBOL, UNIT, STOP);
6130     } else if (IS (p, BY_SYMBOL)) {
6131       reduce (p, NO_NOTE, NO_TICK, BY_PART, BY_SYMBOL, UNIT, STOP);
6132     } else if (IS (p, TO_SYMBOL)) {
6133       reduce (p, NO_NOTE, NO_TICK, TO_PART, TO_SYMBOL, UNIT, STOP);
6134     } else if (IS (p, DOWNTO_SYMBOL)) {
6135       reduce (p, NO_NOTE, NO_TICK, TO_PART, DOWNTO_SYMBOL, UNIT, STOP);
6136     } else if (IS (p, WHILE_SYMBOL)) {
6137       reduce (p, NO_NOTE, NO_TICK, WHILE_PART, WHILE_SYMBOL, ENQUIRY_CLAUSE, STOP);
6138       reduce (p, empty_clause, NO_TICK, WHILE_PART, WHILE_SYMBOL, INITIALISER_SERIES, STOP);
6139     } else if (IS (p, UNTIL_SYMBOL)) {
6140       reduce (p, NO_NOTE, NO_TICK, UNTIL_PART, UNTIL_SYMBOL, ENQUIRY_CLAUSE, STOP);
6141       reduce (p, empty_clause, NO_TICK, UNTIL_PART, UNTIL_SYMBOL, INITIALISER_SERIES, STOP);
6142     } else if (IS (p, DO_SYMBOL)) {
6143       reduce (p, NO_NOTE, NO_TICK, DO_PART, DO_SYMBOL, SERIAL_CLAUSE, UNTIL_PART, OD_SYMBOL, STOP);
6144       reduce (p, NO_NOTE, NO_TICK, DO_PART, DO_SYMBOL, SERIAL_CLAUSE, OD_SYMBOL, STOP);
6145       reduce (p, NO_NOTE, NO_TICK, DO_PART, DO_SYMBOL, UNTIL_PART, OD_SYMBOL, STOP);
6146     } else if (IS (p, ALT_DO_SYMBOL)) {
6147       reduce (p, NO_NOTE, NO_TICK, ALT_DO_PART, ALT_DO_SYMBOL, SERIAL_CLAUSE, UNTIL_PART, OD_SYMBOL, STOP);
6148       reduce (p, NO_NOTE, NO_TICK, ALT_DO_PART, ALT_DO_SYMBOL, SERIAL_CLAUSE, OD_SYMBOL, STOP);
6149       reduce (p, NO_NOTE, NO_TICK, ALT_DO_PART, ALT_DO_SYMBOL, UNTIL_PART, OD_SYMBOL, STOP);
6150     }
6151   }
6152   p = q;
6153   if (SUB (p) != NO_NODE) {
6154     if (IS (p, OPEN_PART)) {
6155       reduce (p, NO_NOTE, NO_TICK, CONDITIONAL_CLAUSE, OPEN_PART, CHOICE, CHOICE, CLOSE_SYMBOL, STOP);
6156       reduce (p, NO_NOTE, NO_TICK, CONDITIONAL_CLAUSE, OPEN_PART, CHOICE, CLOSE_SYMBOL, STOP);
6157       reduce (p, NO_NOTE, NO_TICK, CONDITIONAL_CLAUSE, OPEN_PART, CHOICE, BRIEF_ELIF_PART, STOP);
6158       reduce (p, NO_NOTE, NO_TICK, CASE_CLAUSE, OPEN_PART, CASE_CHOICE_CLAUSE, CHOICE, CLOSE_SYMBOL, STOP);
6159       reduce (p, NO_NOTE, NO_TICK, CASE_CLAUSE, OPEN_PART, CASE_CHOICE_CLAUSE, CLOSE_SYMBOL, STOP);
6160       reduce (p, NO_NOTE, NO_TICK, CASE_CLAUSE, OPEN_PART, CASE_CHOICE_CLAUSE, BRIEF_OUSE_PART, STOP);
6161       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_CLAUSE, OPEN_PART, CONFORMITY_CHOICE, CHOICE, CLOSE_SYMBOL, STOP);
6162       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_CLAUSE, OPEN_PART, CONFORMITY_CHOICE, CLOSE_SYMBOL, STOP);
6163       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_CLAUSE, OPEN_PART, CONFORMITY_CHOICE, BRIEF_CONFORMITY_OUSE_PART, STOP);
6164     } else if (IS (p, ELSE_OPEN_PART)) {
6165       reduce (p, NO_NOTE, NO_TICK, BRIEF_ELIF_PART, ELSE_OPEN_PART, CHOICE, CHOICE, CLOSE_SYMBOL, STOP);
6166       reduce (p, NO_NOTE, NO_TICK, BRIEF_ELIF_PART, ELSE_OPEN_PART, CHOICE, CLOSE_SYMBOL, STOP);
6167       reduce (p, NO_NOTE, NO_TICK, BRIEF_ELIF_PART, ELSE_OPEN_PART, CHOICE, BRIEF_ELIF_PART, STOP);
6168       reduce (p, NO_NOTE, NO_TICK, BRIEF_OUSE_PART, ELSE_OPEN_PART, CASE_CHOICE_CLAUSE, CHOICE, CLOSE_SYMBOL, STOP);
6169       reduce (p, NO_NOTE, NO_TICK, BRIEF_OUSE_PART, ELSE_OPEN_PART, CASE_CHOICE_CLAUSE, CLOSE_SYMBOL, STOP);
6170       reduce (p, NO_NOTE, NO_TICK, BRIEF_OUSE_PART, ELSE_OPEN_PART, CASE_CHOICE_CLAUSE, BRIEF_OUSE_PART, STOP);
6171       reduce (p, NO_NOTE, NO_TICK, BRIEF_CONFORMITY_OUSE_PART, ELSE_OPEN_PART, CONFORMITY_CHOICE, CHOICE, CLOSE_SYMBOL, STOP);
6172       reduce (p, NO_NOTE, NO_TICK, BRIEF_CONFORMITY_OUSE_PART, ELSE_OPEN_PART, CONFORMITY_CHOICE, CLOSE_SYMBOL, STOP);
6173       reduce (p, NO_NOTE, NO_TICK, BRIEF_CONFORMITY_OUSE_PART, ELSE_OPEN_PART, CONFORMITY_CHOICE, BRIEF_CONFORMITY_OUSE_PART, STOP);
6174     } else if (IS (p, IF_PART)) {
6175       reduce (p, NO_NOTE, NO_TICK, CONDITIONAL_CLAUSE, IF_PART, THEN_PART, ELSE_PART, FI_SYMBOL, STOP);
6176       reduce (p, NO_NOTE, NO_TICK, CONDITIONAL_CLAUSE, IF_PART, THEN_PART, ELIF_PART, STOP);
6177       reduce (p, NO_NOTE, NO_TICK, CONDITIONAL_CLAUSE, IF_PART, THEN_PART, FI_SYMBOL, STOP);
6178     } else if (IS (p, ELIF_IF_PART)) {
6179       reduce (p, NO_NOTE, NO_TICK, ELIF_PART, ELIF_IF_PART, THEN_PART, ELSE_PART, FI_SYMBOL, STOP);
6180       reduce (p, NO_NOTE, NO_TICK, ELIF_PART, ELIF_IF_PART, THEN_PART, FI_SYMBOL, STOP);
6181       reduce (p, NO_NOTE, NO_TICK, ELIF_PART, ELIF_IF_PART, THEN_PART, ELIF_PART, STOP);
6182     } else if (IS (p, CASE_PART)) {
6183       reduce (p, NO_NOTE, NO_TICK, CASE_CLAUSE, CASE_PART, CASE_IN_PART, OUT_PART, ESAC_SYMBOL, STOP);
6184       reduce (p, NO_NOTE, NO_TICK, CASE_CLAUSE, CASE_PART, CASE_IN_PART, ESAC_SYMBOL, STOP);
6185       reduce (p, NO_NOTE, NO_TICK, CASE_CLAUSE, CASE_PART, CASE_IN_PART, CASE_OUSE_PART, STOP);
6186       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_CLAUSE, CASE_PART, CONFORMITY_IN_PART, OUT_PART, ESAC_SYMBOL, STOP);
6187       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_CLAUSE, CASE_PART, CONFORMITY_IN_PART, ESAC_SYMBOL, STOP);
6188       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_CLAUSE, CASE_PART, CONFORMITY_IN_PART, CONFORMITY_OUSE_PART, STOP);
6189     } else if (IS (p, OUSE_PART)) {
6190       reduce (p, NO_NOTE, NO_TICK, CASE_OUSE_PART, OUSE_PART, CASE_IN_PART, OUT_PART, ESAC_SYMBOL, STOP);
6191       reduce (p, NO_NOTE, NO_TICK, CASE_OUSE_PART, OUSE_PART, CASE_IN_PART, ESAC_SYMBOL, STOP);
6192       reduce (p, NO_NOTE, NO_TICK, CASE_OUSE_PART, OUSE_PART, CASE_IN_PART, CASE_OUSE_PART, STOP);
6193       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_OUSE_PART, OUSE_PART, CONFORMITY_IN_PART, OUT_PART, ESAC_SYMBOL, STOP);
6194       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_OUSE_PART, OUSE_PART, CONFORMITY_IN_PART, ESAC_SYMBOL, STOP);
6195       reduce (p, NO_NOTE, NO_TICK, CONFORMITY_OUSE_PART, OUSE_PART, CONFORMITY_IN_PART, CONFORMITY_OUSE_PART, STOP);
6196     } else if (IS (p, FOR_PART)) {
6197       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, FROM_PART, BY_PART, TO_PART, WHILE_PART, ALT_DO_PART, STOP);
6198       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, FROM_PART, BY_PART, WHILE_PART, ALT_DO_PART, STOP);
6199       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, FROM_PART, TO_PART, WHILE_PART, ALT_DO_PART, STOP);
6200       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, FROM_PART, WHILE_PART, ALT_DO_PART, STOP);
6201       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, BY_PART, TO_PART, WHILE_PART, ALT_DO_PART, STOP);
6202       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, BY_PART, WHILE_PART, ALT_DO_PART, STOP);
6203       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, TO_PART, WHILE_PART, ALT_DO_PART, STOP);
6204       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, WHILE_PART, ALT_DO_PART, STOP);
6205       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, FROM_PART, BY_PART, TO_PART, ALT_DO_PART, STOP);
6206       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, FROM_PART, BY_PART, ALT_DO_PART, STOP);
6207       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, FROM_PART, TO_PART, ALT_DO_PART, STOP);
6208       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, FROM_PART, ALT_DO_PART, STOP);
6209       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, BY_PART, TO_PART, ALT_DO_PART, STOP);
6210       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, BY_PART, ALT_DO_PART, STOP);
6211       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, TO_PART, ALT_DO_PART, STOP);
6212       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FOR_PART, ALT_DO_PART, STOP);
6213     } else if (IS (p, FROM_PART)) {
6214       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FROM_PART, BY_PART, TO_PART, WHILE_PART, ALT_DO_PART, STOP);
6215       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FROM_PART, BY_PART, WHILE_PART, ALT_DO_PART, STOP);
6216       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FROM_PART, TO_PART, WHILE_PART, ALT_DO_PART, STOP);
6217       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FROM_PART, WHILE_PART, ALT_DO_PART, STOP);
6218       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FROM_PART, BY_PART, TO_PART, ALT_DO_PART, STOP);
6219       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FROM_PART, BY_PART, ALT_DO_PART, STOP);
6220       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FROM_PART, TO_PART, ALT_DO_PART, STOP);
6221       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, FROM_PART, ALT_DO_PART, STOP);
6222     } else if (IS (p, BY_PART)) {
6223       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, BY_PART, TO_PART, WHILE_PART, ALT_DO_PART, STOP);
6224       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, BY_PART, WHILE_PART, ALT_DO_PART, STOP);
6225       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, BY_PART, TO_PART, ALT_DO_PART, STOP);
6226       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, BY_PART, ALT_DO_PART, STOP);
6227     } else if (IS (p, TO_PART)) {
6228       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, TO_PART, WHILE_PART, ALT_DO_PART, STOP);
6229       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, TO_PART, ALT_DO_PART, STOP);
6230     } else if (IS (p, WHILE_PART)) {
6231       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, WHILE_PART, ALT_DO_PART, STOP);
6232     } else if (IS (p, DO_PART)) {
6233       reduce (p, NO_NOTE, NO_TICK, LOOP_CLAUSE, DO_PART, STOP);
6234     }
6235   }
6236 }
6237 
6238 /**
6239 @brief Substitute reduction when a phrase could not be parsed.
6240 @param p Node in syntax tree.
6241 @param expect Information the parser may have on what is expected.
6242 @param suppress Suppresses a diagnostic_node message (nested c.q. related diagnostics).
6243 **/
6244 
6245 static void
recover_from_error(NODE_T * p,int expect,BOOL_T suppress)6246 recover_from_error (NODE_T * p, int expect, BOOL_T suppress)
6247 {
6248 /* This routine does not do fancy things as that might introduce more errors */
6249   NODE_T *q = p;
6250   if (p == NO_NODE) {
6251     return;
6252   }
6253   if (expect == SOME_CLAUSE) {
6254     expect = serial_or_collateral (p);
6255   }
6256   if (!suppress) {
6257 /* Give an error message */
6258     NODE_T *w = p;
6259     char *seq = phrase_to_text (p, &w);
6260     if (strlen (seq) == 0) {
6261       if (ERROR_COUNT (&program) == 0) {
6262         diagnostic_node (A68_SYNTAX_ERROR, w, ERROR_SYNTAX_EXPECTED, expect);
6263       }
6264     } else {
6265       diagnostic_node (A68_SYNTAX_ERROR, w, ERROR_INVALID_SEQUENCE, seq, expect);
6266     }
6267     if (ERROR_COUNT (&program) >= MAX_ERRORS) {
6268       longjmp (bottom_up_crash_exit, 1);
6269     }
6270   }
6271 /* Try to prevent spurious diagnostics by guessing what was expected */
6272   while (NEXT (q) != NO_NODE) {
6273     FORWARD (q);
6274   }
6275   if (is_one_of (p, BEGIN_SYMBOL, OPEN_SYMBOL, STOP)) {
6276     if (expect == ARGUMENT || expect == COLLATERAL_CLAUSE || expect == PARAMETER_PACK || expect == STRUCTURE_PACK || expect == UNION_PACK) {
6277       make_sub (p, q, expect);
6278     } else if (expect == ENQUIRY_CLAUSE) {
6279       make_sub (p, q, OPEN_PART);
6280     } else if (expect == FORMAL_DECLARERS) {
6281       make_sub (p, q, FORMAL_DECLARERS);
6282     } else {
6283       make_sub (p, q, CLOSED_CLAUSE);
6284     }
6285   } else if (IS (p, FORMAT_DELIMITER_SYMBOL) && expect == FORMAT_TEXT) {
6286     make_sub (p, q, FORMAT_TEXT);
6287   } else if (IS (p, CODE_SYMBOL)) {
6288     make_sub (p, q, CODE_CLAUSE);
6289   } else if (is_one_of (p, THEN_BAR_SYMBOL, CHOICE, STOP)) {
6290     make_sub (p, q, CHOICE);
6291   } else if (is_one_of (p, IF_SYMBOL, IF_PART, STOP)) {
6292     make_sub (p, q, IF_PART);
6293   } else if (is_one_of (p, THEN_SYMBOL, THEN_PART, STOP)) {
6294     make_sub (p, q, THEN_PART);
6295   } else if (is_one_of (p, ELSE_SYMBOL, ELSE_PART, STOP)) {
6296     make_sub (p, q, ELSE_PART);
6297   } else if (is_one_of (p, ELIF_SYMBOL, ELIF_IF_PART, STOP)) {
6298     make_sub (p, q, ELIF_IF_PART);
6299   } else if (is_one_of (p, CASE_SYMBOL, CASE_PART, STOP)) {
6300     make_sub (p, q, CASE_PART);
6301   } else if (is_one_of (p, OUT_SYMBOL, OUT_PART, STOP)) {
6302     make_sub (p, q, OUT_PART);
6303   } else if (is_one_of (p, OUSE_SYMBOL, OUSE_PART, STOP)) {
6304     make_sub (p, q, OUSE_PART);
6305   } else if (is_one_of (p, FOR_SYMBOL, FOR_PART, STOP)) {
6306     make_sub (p, q, FOR_PART);
6307   } else if (is_one_of (p, FROM_SYMBOL, FROM_PART, STOP)) {
6308     make_sub (p, q, FROM_PART);
6309   } else if (is_one_of (p, BY_SYMBOL, BY_PART, STOP)) {
6310     make_sub (p, q, BY_PART);
6311   } else if (is_one_of (p, TO_SYMBOL, DOWNTO_SYMBOL, TO_PART, STOP)) {
6312     make_sub (p, q, TO_PART);
6313   } else if (is_one_of (p, WHILE_SYMBOL, WHILE_PART, STOP)) {
6314     make_sub (p, q, WHILE_PART);
6315   } else if (is_one_of (p, UNTIL_SYMBOL, UNTIL_PART, STOP)) {
6316     make_sub (p, q, UNTIL_PART);
6317   } else if (is_one_of (p, DO_SYMBOL, DO_PART, STOP)) {
6318     make_sub (p, q, DO_PART);
6319   } else if (is_one_of (p, ALT_DO_SYMBOL, ALT_DO_PART, STOP)) {
6320     make_sub (p, q, ALT_DO_PART);
6321   } else if (non_terminal_string (edit_line, expect) != NO_TEXT) {
6322     make_sub (p, q, expect);
6323   }
6324 }
6325 
6326 /**
6327 @brief Heuristic aid in pinpointing errors.
6328 @param p Node in syntax tree.
6329 **/
6330 
6331 static void
reduce_erroneous_units(NODE_T * p)6332 reduce_erroneous_units (NODE_T * p)
6333 {
6334 /* Constructs are reduced to units in an attempt to limit spurious diagnostics */
6335   NODE_T *q;
6336   for (q = p; q != NO_NODE; FORWARD (q)) {
6337 /* Some implementations allow selection from a tertiary, when there is no risk
6338 of ambiguity. Algol68G follows RR, so some extra attention here to guide an
6339 unsuspecting user */
6340     if (whether (q, SELECTOR, -SECONDARY, STOP)) {
6341       diagnostic_node (A68_SYNTAX_ERROR, NEXT (q), ERROR_SYNTAX_EXPECTED, SECONDARY);
6342       reduce (q, NO_NOTE, NO_TICK, UNIT, SELECTOR, WILDCARD, STOP);
6343     }
6344 /* Attention for identity relations that require tertiaries */
6345     if (whether (q, -TERTIARY, IS_SYMBOL, TERTIARY, STOP) || whether (q, TERTIARY, IS_SYMBOL, -TERTIARY, STOP) || whether (q, -TERTIARY, IS_SYMBOL, -TERTIARY, STOP)) {
6346       diagnostic_node (A68_SYNTAX_ERROR, NEXT (q), ERROR_SYNTAX_EXPECTED, TERTIARY);
6347       reduce (q, NO_NOTE, NO_TICK, UNIT, WILDCARD, IS_SYMBOL, WILDCARD, STOP);
6348     } else if (whether (q, -TERTIARY, ISNT_SYMBOL, TERTIARY, STOP) || whether (q, TERTIARY, ISNT_SYMBOL, -TERTIARY, STOP) || whether (q, -TERTIARY, ISNT_SYMBOL, -TERTIARY, STOP)) {
6349       diagnostic_node (A68_SYNTAX_ERROR, NEXT (q), ERROR_SYNTAX_EXPECTED, TERTIARY);
6350       reduce (q, NO_NOTE, NO_TICK, UNIT, WILDCARD, ISNT_SYMBOL, WILDCARD, STOP);
6351     }
6352   }
6353 }
6354 
6355 /* A posteriori checks of the syntax tree built by the BU parser */
6356 
6357 /**
6358 @brief Driver for a posteriori error checking.
6359 @param p Node in syntax tree.
6360 **/
6361 
6362 void
bottom_up_error_check(NODE_T * p)6363 bottom_up_error_check (NODE_T * p)
6364 {
6365   for (; p != NO_NODE; FORWARD (p)) {
6366     if (IS (p, BOOLEAN_PATTERN)) {
6367       int k = 0;
6368       count_pictures (SUB (p), &k);
6369       if (!(k == 0 || k == 2)) {
6370         diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_FORMAT_PICTURE_NUMBER, ATTRIBUTE (p));
6371       }
6372     } else {
6373       bottom_up_error_check (SUB (p));
6374     }
6375   }
6376 }
6377 
6378 /* Next part rearranges and checks the tree after the symbol tables are finished */
6379 
6380 /**
6381 @brief Transfer IDENTIFIER to JUMP where appropriate.
6382 @param p Node in syntax tree.
6383 **/
6384 
6385 void
rearrange_goto_less_jumps(NODE_T * p)6386 rearrange_goto_less_jumps (NODE_T * p)
6387 {
6388   for (; p != NO_NODE; FORWARD (p)) {
6389     if (IS (p, UNIT)) {
6390       NODE_T *q = SUB (p);
6391       if (IS (q, TERTIARY)) {
6392         NODE_T *tertiary = q;
6393         q = SUB (q);
6394         if (q != NO_NODE && IS (q, SECONDARY)) {
6395           q = SUB (q);
6396           if (q != NO_NODE && IS (q, PRIMARY)) {
6397             q = SUB (q);
6398             if (q != NO_NODE && IS (q, IDENTIFIER)) {
6399               if (is_identifier_or_label_global (TABLE (q), NSYMBOL (q)) == LABEL) {
6400                 ATTRIBUTE (tertiary) = JUMP;
6401                 SUB (tertiary) = q;
6402               }
6403             }
6404           }
6405         }
6406       }
6407     } else if (IS (p, TERTIARY)) {
6408       NODE_T *q = SUB (p);
6409       if (q != NO_NODE && IS (q, SECONDARY)) {
6410         NODE_T *secondary = q;
6411         q = SUB (q);
6412         if (q != NO_NODE && IS (q, PRIMARY)) {
6413           q = SUB (q);
6414           if (q != NO_NODE && IS (q, IDENTIFIER)) {
6415             if (is_identifier_or_label_global (TABLE (q), NSYMBOL (q)) == LABEL) {
6416               ATTRIBUTE (secondary) = JUMP;
6417               SUB (secondary) = q;
6418             }
6419           }
6420         }
6421       }
6422     } else if (IS (p, SECONDARY)) {
6423       NODE_T *q = SUB (p);
6424       if (q != NO_NODE && IS (q, PRIMARY)) {
6425         NODE_T *primary = q;
6426         q = SUB (q);
6427         if (q != NO_NODE && IS (q, IDENTIFIER)) {
6428           if (is_identifier_or_label_global (TABLE (q), NSYMBOL (q)) == LABEL) {
6429             ATTRIBUTE (primary) = JUMP;
6430             SUB (primary) = q;
6431           }
6432         }
6433       }
6434     } else if (IS (p, PRIMARY)) {
6435       NODE_T *q = SUB (p);
6436       if (q != NO_NODE && IS (q, IDENTIFIER)) {
6437         if (is_identifier_or_label_global (TABLE (q), NSYMBOL (q)) == LABEL) {
6438           make_sub (q, q, JUMP);
6439         }
6440       }
6441     }
6442     rearrange_goto_less_jumps (SUB (p));
6443   }
6444 }
6445 
6446 /***********************************************************/
6447 /* VICTAL checker for formal, actual and virtual declarers */
6448 /***********************************************************/
6449 
6450 /**
6451 @brief Check generator.
6452 @param p Node in syntax tree.
6453 **/
6454 
6455 static void
victal_check_generator(NODE_T * p)6456 victal_check_generator (NODE_T * p)
6457 {
6458   if (!victal_check_declarer (NEXT (p), ACTUAL_DECLARER_MARK)) {
6459     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "actual declarer");
6460   }
6461 }
6462 
6463 /**
6464 @brief Check formal pack.
6465 @param p Node in syntax tree.
6466 @param x Expected attribute.
6467 @param z Flag.
6468 **/
6469 
6470 static void
victal_check_formal_pack(NODE_T * p,int x,BOOL_T * z)6471 victal_check_formal_pack (NODE_T * p, int x, BOOL_T * z)
6472 {
6473   if (p != NO_NODE) {
6474     if (IS (p, FORMAL_DECLARERS)) {
6475       victal_check_formal_pack (SUB (p), x, z);
6476     } else if (is_one_of (p, OPEN_SYMBOL, COMMA_SYMBOL, STOP)) {
6477       victal_check_formal_pack (NEXT (p), x, z);
6478     } else if (IS (p, FORMAL_DECLARERS_LIST)) {
6479       victal_check_formal_pack (NEXT (p), x, z);
6480       victal_check_formal_pack (SUB (p), x, z);
6481     } else if (IS (p, DECLARER)) {
6482       victal_check_formal_pack (NEXT (p), x, z);
6483       (*z) &= victal_check_declarer (SUB (p), x);
6484     }
6485   }
6486 }
6487 
6488 /**
6489 @brief Check operator declaration.
6490 @param p Node in syntax tree.
6491 **/
6492 
6493 static void
victal_check_operator_dec(NODE_T * p)6494 victal_check_operator_dec (NODE_T * p)
6495 {
6496   if (IS (NEXT (p), FORMAL_DECLARERS)) {
6497     BOOL_T z = A68_TRUE;
6498     victal_check_formal_pack (NEXT (p), FORMAL_DECLARER_MARK, &z);
6499     if (!z) {
6500       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarers");
6501     }
6502     FORWARD (p);
6503   }
6504   if (!victal_check_declarer (NEXT (p), FORMAL_DECLARER_MARK)) {
6505     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarer");
6506   }
6507 }
6508 
6509 /**
6510 @brief Check mode declaration.
6511 @param p Node in syntax tree.
6512 **/
6513 
6514 static void
victal_check_mode_dec(NODE_T * p)6515 victal_check_mode_dec (NODE_T * p)
6516 {
6517   if (p != NO_NODE) {
6518     if (IS (p, MODE_DECLARATION)) {
6519       victal_check_mode_dec (SUB (p));
6520       victal_check_mode_dec (NEXT (p));
6521     } else if (is_one_of (p, MODE_SYMBOL, DEFINING_INDICANT, STOP)
6522                || is_one_of (p, EQUALS_SYMBOL, COMMA_SYMBOL, STOP)) {
6523       victal_check_mode_dec (NEXT (p));
6524     } else if (IS (p, DECLARER)) {
6525       if (!victal_check_declarer (p, ACTUAL_DECLARER_MARK)) {
6526         diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "actual declarer");
6527       }
6528     }
6529   }
6530 }
6531 
6532 /**
6533 @brief Check variable declaration.
6534 @param p Node in syntax tree.
6535 **/
6536 
6537 static void
victal_check_variable_dec(NODE_T * p)6538 victal_check_variable_dec (NODE_T * p)
6539 {
6540   if (p != NO_NODE) {
6541     if (IS (p, VARIABLE_DECLARATION)) {
6542       victal_check_variable_dec (SUB (p));
6543       victal_check_variable_dec (NEXT (p));
6544     } else if (is_one_of (p, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, STOP)
6545                || IS (p, COMMA_SYMBOL)) {
6546       victal_check_variable_dec (NEXT (p));
6547     } else if (IS (p, UNIT)) {
6548       victal_checker (SUB (p));
6549     } else if (IS (p, DECLARER)) {
6550       if (!victal_check_declarer (p, ACTUAL_DECLARER_MARK)) {
6551         diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "actual declarer");
6552       }
6553       victal_check_variable_dec (NEXT (p));
6554     }
6555   }
6556 }
6557 
6558 /**
6559 @brief Check identity declaration.
6560 @param p Node in syntax tree.
6561 **/
6562 
6563 static void
victal_check_identity_dec(NODE_T * p)6564 victal_check_identity_dec (NODE_T * p)
6565 {
6566   if (p != NO_NODE) {
6567     if (IS (p, IDENTITY_DECLARATION)) {
6568       victal_check_identity_dec (SUB (p));
6569       victal_check_identity_dec (NEXT (p));
6570     } else if (is_one_of (p, DEFINING_IDENTIFIER, EQUALS_SYMBOL, COMMA_SYMBOL, STOP)) {
6571       victal_check_identity_dec (NEXT (p));
6572     } else if (IS (p, UNIT)) {
6573       victal_checker (SUB (p));
6574     } else if (IS (p, DECLARER)) {
6575       if (!victal_check_declarer (p, FORMAL_DECLARER_MARK)) {
6576         diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarer");
6577       }
6578       victal_check_identity_dec (NEXT (p));
6579     }
6580   }
6581 }
6582 
6583 /**
6584 @brief Check routine pack.
6585 @param p Node in syntax tree.
6586 @param x Expected attribute.
6587 @param z Flag.
6588 **/
6589 
6590 static void
victal_check_routine_pack(NODE_T * p,int x,BOOL_T * z)6591 victal_check_routine_pack (NODE_T * p, int x, BOOL_T * z)
6592 {
6593   if (p != NO_NODE) {
6594     if (IS (p, PARAMETER_PACK)) {
6595       victal_check_routine_pack (SUB (p), x, z);
6596     } else if (is_one_of (p, OPEN_SYMBOL, COMMA_SYMBOL, STOP)) {
6597       victal_check_routine_pack (NEXT (p), x, z);
6598     } else if (is_one_of (p, PARAMETER_LIST, PARAMETER, STOP)) {
6599       victal_check_routine_pack (NEXT (p), x, z);
6600       victal_check_routine_pack (SUB (p), x, z);
6601     } else if (IS (p, DECLARER)) {
6602       *z &= victal_check_declarer (SUB (p), x);
6603     }
6604   }
6605 }
6606 
6607 /**
6608 @brief Check routine text.
6609 @param p Node in syntax tree.
6610 **/
6611 
6612 static void
victal_check_routine_text(NODE_T * p)6613 victal_check_routine_text (NODE_T * p)
6614 {
6615   if (IS (p, PARAMETER_PACK)) {
6616     BOOL_T z = A68_TRUE;
6617     victal_check_routine_pack (p, FORMAL_DECLARER_MARK, &z);
6618     if (!z) {
6619       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarers");
6620     }
6621     FORWARD (p);
6622   }
6623   if (!victal_check_declarer (p, FORMAL_DECLARER_MARK)) {
6624     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarer");
6625   }
6626   victal_checker (NEXT (p));
6627 }
6628 
6629 /**
6630 @brief Check structure pack.
6631 @param p Node in syntax tree.
6632 @param x Expected attribute.
6633 @param z Flag.
6634 **/
6635 
6636 static void
victal_check_structure_pack(NODE_T * p,int x,BOOL_T * z)6637 victal_check_structure_pack (NODE_T * p, int x, BOOL_T * z)
6638 {
6639   if (p != NO_NODE) {
6640     if (IS (p, STRUCTURE_PACK)) {
6641       victal_check_structure_pack (SUB (p), x, z);
6642     } else if (is_one_of (p, OPEN_SYMBOL, COMMA_SYMBOL, STOP)) {
6643       victal_check_structure_pack (NEXT (p), x, z);
6644     } else if (is_one_of (p, STRUCTURED_FIELD_LIST, STRUCTURED_FIELD, STOP)) {
6645       victal_check_structure_pack (NEXT (p), x, z);
6646       victal_check_structure_pack (SUB (p), x, z);
6647     } else if (IS (p, DECLARER)) {
6648       (*z) &= victal_check_declarer (SUB (p), x);
6649     }
6650   }
6651 }
6652 
6653 /**
6654 @brief Check union pack.
6655 @param p Node in syntax tree.
6656 @param x Expected attribute.
6657 @param z Flag.
6658 **/
6659 
6660 static void
victal_check_union_pack(NODE_T * p,int x,BOOL_T * z)6661 victal_check_union_pack (NODE_T * p, int x, BOOL_T * z)
6662 {
6663   if (p != NO_NODE) {
6664     if (IS (p, UNION_PACK)) {
6665       victal_check_union_pack (SUB (p), x, z);
6666     } else if (is_one_of (p, OPEN_SYMBOL, COMMA_SYMBOL, VOID_SYMBOL, STOP)) {
6667       victal_check_union_pack (NEXT (p), x, z);
6668     } else if (IS (p, UNION_DECLARER_LIST)) {
6669       victal_check_union_pack (NEXT (p), x, z);
6670       victal_check_union_pack (SUB (p), x, z);
6671     } else if (IS (p, DECLARER)) {
6672       victal_check_union_pack (NEXT (p), x, z);
6673       (*z) &= victal_check_declarer (SUB (p), FORMAL_DECLARER_MARK);
6674     }
6675   }
6676 }
6677 
6678 /**
6679 @brief Check declarer.
6680 @param p Node in syntax tree.
6681 @param x Expected attribute.
6682 **/
6683 
6684 static BOOL_T
victal_check_declarer(NODE_T * p,int x)6685 victal_check_declarer (NODE_T * p, int x)
6686 {
6687   if (p == NO_NODE) {
6688     return (A68_FALSE);
6689   } else if (IS (p, DECLARER)) {
6690     return (victal_check_declarer (SUB (p), x));
6691   } else if (is_one_of (p, LONGETY, SHORTETY, STOP)) {
6692     return (A68_TRUE);
6693   } else if (is_one_of (p, VOID_SYMBOL, INDICANT, STANDARD, STOP)) {
6694     return (A68_TRUE);
6695   } else if (IS (p, REF_SYMBOL)) {
6696     return (victal_check_declarer (NEXT (p), VIRTUAL_DECLARER_MARK));
6697   } else if (IS (p, FLEX_SYMBOL)) {
6698     return (victal_check_declarer (NEXT (p), x));
6699   } else if (IS (p, BOUNDS)) {
6700     victal_checker (SUB (p));
6701     if (x == FORMAL_DECLARER_MARK) {
6702       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal bounds");
6703       (void) victal_check_declarer (NEXT (p), x);
6704       return (A68_TRUE);
6705     } else if (x == VIRTUAL_DECLARER_MARK) {
6706       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "virtual bounds");
6707       (void) victal_check_declarer (NEXT (p), x);
6708       return (A68_TRUE);
6709     } else {
6710       return (victal_check_declarer (NEXT (p), x));
6711     }
6712   } else if (IS (p, FORMAL_BOUNDS)) {
6713     victal_checker (SUB (p));
6714     if (x == ACTUAL_DECLARER_MARK) {
6715       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "actual bounds");
6716       (void) victal_check_declarer (NEXT (p), x);
6717       return (A68_TRUE);
6718     } else {
6719       return (victal_check_declarer (NEXT (p), x));
6720     }
6721   } else if (IS (p, STRUCT_SYMBOL)) {
6722     BOOL_T z = A68_TRUE;
6723     victal_check_structure_pack (NEXT (p), x, &z);
6724     return (z);
6725   } else if (IS (p, UNION_SYMBOL)) {
6726     BOOL_T z = A68_TRUE;
6727     victal_check_union_pack (NEXT (p), FORMAL_DECLARER_MARK, &z);
6728     if (!z) {
6729       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarer pack");
6730     }
6731     return (A68_TRUE);
6732   } else if (IS (p, PROC_SYMBOL)) {
6733     if (IS (NEXT (p), FORMAL_DECLARERS)) {
6734       BOOL_T z = A68_TRUE;
6735       victal_check_formal_pack (NEXT (p), FORMAL_DECLARER_MARK, &z);
6736       if (!z) {
6737         diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarer");
6738       }
6739       FORWARD (p);
6740     }
6741     if (!victal_check_declarer (NEXT (p), FORMAL_DECLARER_MARK)) {
6742       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarer");
6743     }
6744     return (A68_TRUE);
6745   } else {
6746     return (A68_FALSE);
6747   }
6748 }
6749 
6750 /**
6751 @brief Check cast.
6752 @param p Node in syntax tree.
6753 **/
6754 
6755 static void
victal_check_cast(NODE_T * p)6756 victal_check_cast (NODE_T * p)
6757 {
6758   if (!victal_check_declarer (p, FORMAL_DECLARER_MARK)) {
6759     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_EXPECTED, "formal declarer");
6760     victal_checker (NEXT (p));
6761   }
6762 }
6763 
6764 /**
6765 @brief Driver for checking VICTALITY of declarers.
6766 @param p Node in syntax tree.
6767 **/
6768 
6769 void
victal_checker(NODE_T * p)6770 victal_checker (NODE_T * p)
6771 {
6772   for (; p != NO_NODE; FORWARD (p)) {
6773     if (IS (p, MODE_DECLARATION)) {
6774       victal_check_mode_dec (SUB (p));
6775     } else if (IS (p, VARIABLE_DECLARATION)) {
6776       victal_check_variable_dec (SUB (p));
6777     } else if (IS (p, IDENTITY_DECLARATION)) {
6778       victal_check_identity_dec (SUB (p));
6779     } else if (IS (p, GENERATOR)) {
6780       victal_check_generator (SUB (p));
6781     } else if (IS (p, ROUTINE_TEXT)) {
6782       victal_check_routine_text (SUB (p));
6783     } else if (IS (p, OPERATOR_PLAN)) {
6784       victal_check_operator_dec (SUB (p));
6785     } else if (IS (p, CAST)) {
6786       victal_check_cast (SUB (p));
6787     } else {
6788       victal_checker (SUB (p));
6789     }
6790   }
6791 }
6792 
6793 /****************************************************/
6794 /* Mode collection, equivalencing and derived modes */
6795 /****************************************************/
6796 
6797 /*************************/
6798 /* Mode service routines */
6799 /*************************/
6800 
6801 /**
6802 @brief Reset moid.
6803 @param p Node in syntax tree.
6804 **/
6805 
6806 static void
reset_moid_tree(NODE_T * p)6807 reset_moid_tree (NODE_T * p)
6808 {
6809   for (; p != NO_NODE; FORWARD (p)) {
6810     MOID (p) = NO_MOID;
6811     reset_moid_tree (SUB (p));
6812   }
6813 }
6814 
6815 /**
6816 @brief Renumber moids.
6817 @param p Moid list.
6818 @param n Index.
6819 **/
6820 
6821 void
renumber_moids(MOID_T * p,int n)6822 renumber_moids (MOID_T * p, int n)
6823 {
6824   if (p != NO_MOID) {
6825     NUMBER (p) = n;
6826     renumber_moids (NEXT (p), n + 1);
6827   }
6828 }
6829 
6830 /**************************************************/
6831 /* Routines for establishing equivalence of modes */
6832 /* Routines for adding modes                      */
6833 /**************************************************/
6834 
6835 /*
6836 After the initial version of the mode equivalencer was made to work (1993), I
6837 found: Algol Bulletin 30.3.3 C.H.A. Koster: On infinite modes, 86-89 [1969],
6838 which essentially concurs with the algorithm on mode equivalence I wrote (and
6839 which is still here). It is basic logic anyway: prove equivalence of things
6840 assuming their equivalence.
6841 */
6842 
6843 /**
6844 @brief Whether packs are equivalent, same sequence of equivalence modes.
6845 @param s Pack 1.
6846 @param t Pack 2.
6847 @return See brief description.
6848 **/
6849 
6850 static BOOL_T
is_packs_equivalent(PACK_T * s,PACK_T * t)6851 is_packs_equivalent (PACK_T * s, PACK_T * t)
6852 {
6853   for (; s != NO_PACK && t != NO_PACK; FORWARD (s), FORWARD (t)) {
6854     if (!is_modes_equivalent (MOID (s), MOID (t))) {
6855       return (A68_FALSE);
6856     }
6857     if (TEXT (s) != TEXT (t)) {
6858       return (A68_FALSE);
6859     }
6860   }
6861   return ((BOOL_T) (s == NO_PACK && t == NO_PACK));
6862 }
6863 
6864 /**
6865 @brief Whether packs are equivalent, must be subsets.
6866 @param s Pack 1.
6867 @param t Pack 2.
6868 @return See brief description.
6869 **/
6870 
6871 static BOOL_T
is_united_packs_equivalent(PACK_T * s,PACK_T * t)6872 is_united_packs_equivalent (PACK_T * s, PACK_T * t)
6873 {
6874   PACK_T *p, *q;
6875   BOOL_T f;
6876 /* whether s is a subset of t ... */
6877   for (p = s; p != NO_PACK; FORWARD (p)) {
6878     for (f = A68_FALSE, q = t; q != NO_PACK && !f; FORWARD (q)) {
6879       f = is_modes_equivalent (MOID (p), MOID (q));
6880     }
6881     if (!f) {
6882       return (A68_FALSE);
6883     }
6884   }
6885 /* ... and whether t is a subset of s */
6886   for (p = t; p != NO_PACK; FORWARD (p)) {
6887     for (f = A68_FALSE, q = s; q != NO_PACK && !f; FORWARD (q)) {
6888       f = is_modes_equivalent (MOID (p), MOID (q));
6889     }
6890     if (!f) {
6891       return (A68_FALSE);
6892     }
6893   }
6894   return (A68_TRUE);
6895 }
6896 
6897 /**
6898 @brief Whether moids a and b are structurally equivalent.
6899 @param a Moid.
6900 @param b Moid.
6901 @return See brief description.
6902 **/
6903 
6904 BOOL_T
is_modes_equivalent(MOID_T * a,MOID_T * b)6905 is_modes_equivalent (MOID_T * a, MOID_T * b)
6906 {
6907   if (a == NO_MOID || b == NO_MOID) {
6908 /* Modes can be NO_MOID in partial argument lists */
6909     return (A68_FALSE);
6910   } else if (a == b) {
6911     return (A68_TRUE);
6912   } else if (a == MODE (ERROR) || b == MODE (ERROR)) {
6913     return (A68_FALSE);
6914   } else if (ATTRIBUTE (a) != ATTRIBUTE (b)) {
6915     return (A68_FALSE);
6916   } else if (DIM (a) != DIM (b)) {
6917     return (A68_FALSE);
6918   } else if (IS (a, STANDARD)) {
6919     return ((BOOL_T) (a == b));
6920   } else if (EQUIVALENT (a) == b || EQUIVALENT (b) == a) {
6921     return (A68_TRUE);
6922   } else if (is_postulated_pair (top_postulate, a, b) || is_postulated_pair (top_postulate, b, a)) {
6923     return (A68_TRUE);
6924   } else if (IS (a, INDICANT)) {
6925     if (NODE (a) == NO_NODE || NODE (b) == NO_NODE) {
6926       return (A68_FALSE);
6927     } else {
6928       return (NODE (a) == NODE (b));
6929     }
6930   }
6931   switch (ATTRIBUTE (a)) {
6932   case REF_SYMBOL:
6933   case ROW_SYMBOL:
6934   case FLEX_SYMBOL:{
6935       return (is_modes_equivalent (SUB (a), SUB (b)));
6936     }
6937   }
6938   if (IS (a, PROC_SYMBOL) && PACK (a) == NO_PACK && PACK (b) == NO_PACK) {
6939     return (is_modes_equivalent (SUB (a), SUB (b)));
6940   } else if (IS (a, STRUCT_SYMBOL)) {
6941     POSTULATE_T *save;
6942     BOOL_T z;
6943     save = top_postulate;
6944     make_postulate (&top_postulate, a, b);
6945     z = is_packs_equivalent (PACK (a), PACK (b));
6946     free_postulate_list (top_postulate, save);
6947     top_postulate = save;
6948     return (z);
6949   } else if (IS (a, UNION_SYMBOL)) {
6950     return (is_united_packs_equivalent (PACK (a), PACK (b)));
6951   } else if (IS (a, PROC_SYMBOL) && PACK (a) != NO_PACK && PACK (b) != NO_PACK) {
6952     POSTULATE_T *save;
6953     BOOL_T z;
6954     save = top_postulate;
6955     make_postulate (&top_postulate, a, b);
6956     z = is_modes_equivalent (SUB (a), SUB (b));
6957     if (z) {
6958       z = is_packs_equivalent (PACK (a), PACK (b));
6959     }
6960     free_postulate_list (top_postulate, save);
6961     top_postulate = save;
6962     return (z);
6963   } else if (IS (a, SERIES_MODE) || IS (a, STOWED_MODE)) {
6964     return (is_packs_equivalent (PACK (a), PACK (b)));
6965   }
6966   return (A68_FALSE);
6967 }
6968 
6969 /**
6970 @brief Whether modes 1 and 2 are structurally equivalent.
6971 @param p Mode 1.
6972 @param q Mode 2.
6973 @return See brief description.
6974 **/
6975 
6976 static BOOL_T
prove_moid_equivalence(MOID_T * p,MOID_T * q)6977 prove_moid_equivalence (MOID_T * p, MOID_T * q)
6978 {
6979 /* Prove two modes to be equivalent under assumption that they indeed are */
6980   POSTULATE_T *save = top_postulate;
6981   BOOL_T z = is_modes_equivalent (p, q);
6982   free_postulate_list (top_postulate, save);
6983   top_postulate = save;
6984   return (z);
6985 }
6986 
6987 /**
6988 @brief Register mode in the global mode table, if mode is unique.
6989 @param z Mode table.
6990 @param u Mode to enter.
6991 @return Mode table entry.
6992 **/
6993 
6994 static MOID_T *
register_extra_mode(MOID_T ** z,MOID_T * u)6995 register_extra_mode (MOID_T ** z, MOID_T * u)
6996 {
6997   MOID_T *head = TOP_MOID (&program);
6998 /* If we already know this mode, return the existing entry; otherwise link it in */
6999   for (; head != NO_MOID; FORWARD (head)) {
7000     if (prove_moid_equivalence (head, u)) {
7001       return (head);
7002     }
7003   }
7004 /* Link to chain and exit */
7005   NUMBER (u) = mode_count++;
7006   NEXT (u) = (*z);
7007   return (*z = u);
7008 }
7009 
7010 /**
7011 @brief Add mode "sub" to chain "z".
7012 @param z Chain to insert into.
7013 @param att Attribute.
7014 @param dim Dimension.
7015 @param node Node.
7016 @param sub Subordinate mode.
7017 @param pack Pack.
7018 @return New entry.
7019 **/
7020 
7021 MOID_T *
add_mode(MOID_T ** z,int att,int dim,NODE_T * node,MOID_T * sub,PACK_T * pack)7022 add_mode (MOID_T ** z, int att, int dim, NODE_T * node, MOID_T * sub, PACK_T * pack)
7023 {
7024   MOID_T *new_mode = new_moid ();
7025   ABEND (att == REF_SYMBOL && sub == NO_MOID, ERROR_INTERNAL_CONSISTENCY, "store REF NULL");
7026   ABEND (att == FLEX_SYMBOL && sub == NO_MOID, ERROR_INTERNAL_CONSISTENCY, "store FLEX NULL");
7027   ABEND (att == ROW_SYMBOL && sub == NO_MOID, ERROR_INTERNAL_CONSISTENCY, "store [] NULL");
7028   USE (new_mode) = A68_FALSE;
7029   SIZE (new_mode) = 0;
7030   ATTRIBUTE (new_mode) = att;
7031   DIM (new_mode) = dim;
7032   NODE (new_mode) = node;
7033   HAS_ROWS (new_mode) = (BOOL_T) (att == ROW_SYMBOL);
7034   SUB (new_mode) = sub;
7035   PACK (new_mode) = pack;
7036   NEXT (new_mode) = NO_MOID;
7037   EQUIVALENT (new_mode) = NO_MOID;
7038   SLICE (new_mode) = NO_MOID;
7039   DEFLEXED (new_mode) = NO_MOID;
7040   NAME (new_mode) = NO_MOID;
7041   MULTIPLE (new_mode) = NO_MOID;
7042   ROWED (new_mode) = NO_MOID;
7043   return (register_extra_mode (z, new_mode));
7044 }
7045 
7046 /**
7047 @brief Contract a UNION.
7048 @param u United mode.
7049 **/
7050 
7051 static void
contract_union(MOID_T * u)7052 contract_union (MOID_T * u)
7053 {
7054   PACK_T *s = PACK (u);
7055   for (; s != NO_PACK; FORWARD (s)) {
7056     PACK_T *t = s;
7057     while (t != NO_PACK) {
7058       if (NEXT (t) != NO_PACK && MOID (NEXT (t)) == MOID (s)) {
7059         MOID (t) = MOID (t);
7060         NEXT (t) = NEXT_NEXT (t);
7061       } else {
7062         FORWARD (t);
7063       }
7064     }
7065   }
7066 }
7067 
7068 /**
7069 @brief Absorb UNION pack.
7070 @param u Pack.
7071 @return Absorbed pack.
7072 **/
7073 
7074 static PACK_T *
absorb_union_pack(PACK_T * u)7075 absorb_union_pack (PACK_T * u)
7076 {
7077   BOOL_T go_on;
7078   PACK_T *t, *z;
7079   do {
7080     z = NO_PACK;
7081     go_on = A68_FALSE;
7082     for (t = u; t != NO_PACK; FORWARD (t)) {
7083       if (IS (MOID (t), UNION_SYMBOL)) {
7084         PACK_T *s;
7085         go_on = A68_TRUE;
7086         for (s = PACK (MOID (t)); s != NO_PACK; FORWARD (s)) {
7087           (void) add_mode_to_pack (&z, MOID (s), NO_TEXT, NODE (s));
7088         }
7089       } else {
7090         (void) add_mode_to_pack (&z, MOID (t), NO_TEXT, NODE (t));
7091       }
7092     }
7093     u = z;
7094   } while (go_on);
7095   return (z);
7096 }
7097 
7098 /**
7099 @brief Absorb nested series modes recursively.
7100 @param p Mode.
7101 **/
7102 
7103 static void
absorb_series_pack(MOID_T ** p)7104 absorb_series_pack (MOID_T ** p)
7105 {
7106   BOOL_T go_on;
7107   do {
7108     PACK_T *z = NO_PACK, *t;
7109     go_on = A68_FALSE;
7110     for (t = PACK (*p); t != NO_PACK; FORWARD (t)) {
7111       if (MOID (t) != NO_MOID && IS (MOID (t), SERIES_MODE)) {
7112         PACK_T *s;
7113         go_on = A68_TRUE;
7114         for (s = PACK (MOID (t)); s != NO_PACK; FORWARD (s)) {
7115           add_mode_to_pack (&z, MOID (s), NO_TEXT, NODE (s));
7116         }
7117       } else {
7118         add_mode_to_pack (&z, MOID (t), NO_TEXT, NODE (t));
7119       }
7120     }
7121     PACK (*p) = z;
7122   } while (go_on);
7123 }
7124 
7125 /**
7126 @brief Absorb nested series and united modes recursively.
7127 @param p Mode.
7128 **/
7129 
7130 static void
absorb_series_union_pack(MOID_T ** p)7131 absorb_series_union_pack (MOID_T ** p)
7132 {
7133   BOOL_T go_on;
7134   do {
7135     PACK_T *z = NO_PACK, *t;
7136     go_on = A68_FALSE;
7137     for (t = PACK (*p); t != NO_PACK; FORWARD (t)) {
7138       if (MOID (t) != NO_MOID && (IS (MOID (t), SERIES_MODE) || IS (MOID (t), UNION_SYMBOL))) {
7139         PACK_T *s;
7140         go_on = A68_TRUE;
7141         for (s = PACK (MOID (t)); s != NO_PACK; FORWARD (s)) {
7142           add_mode_to_pack (&z, MOID (s), NO_TEXT, NODE (s));
7143         }
7144       } else {
7145         add_mode_to_pack (&z, MOID (t), NO_TEXT, NODE (t));
7146       }
7147     }
7148     PACK (*p) = z;
7149   } while (go_on);
7150 }
7151 
7152 /**
7153 @brief Make SERIES (u, v).
7154 @param u Mode 1.
7155 @param v Mode 2.
7156 \return SERIES (u, v)
7157 **/
7158 
7159 static MOID_T *
make_series_from_moids(MOID_T * u,MOID_T * v)7160 make_series_from_moids (MOID_T * u, MOID_T * v)
7161 {
7162   MOID_T *x = new_moid ();
7163   ATTRIBUTE (x) = SERIES_MODE;
7164   add_mode_to_pack (&(PACK (x)), u, NO_TEXT, NODE (u));
7165   add_mode_to_pack (&(PACK (x)), v, NO_TEXT, NODE (v));
7166   absorb_series_pack (&x);
7167   DIM (x) = count_pack_members (PACK (x));
7168   (void) register_extra_mode (&TOP_MOID (&program), x);
7169   if (DIM (x) == 1) {
7170     return (MOID (PACK (x)));
7171   } else {
7172     return (x);
7173   }
7174 }
7175 
7176 /**
7177 @brief Absorb firmly related unions in mode.
7178 @param m United mode.
7179 @return Absorbed "m".
7180 **/
7181 
7182 static MOID_T *
absorb_related_subsets(MOID_T * m)7183 absorb_related_subsets (MOID_T * m)
7184 {
7185 /*
7186 For instance invalid UNION (PROC REF UNION (A, B), A, B) -> valid UNION (A, B),
7187 which is used in balancing conformity clauses.
7188 */
7189   int mods;
7190   do {
7191     PACK_T *u = NO_PACK, *v;
7192     mods = 0;
7193     for (v = PACK (m); v != NO_PACK; FORWARD (v)) {
7194       MOID_T *n = depref_completely (MOID (v));
7195       if (IS (n, UNION_SYMBOL) && is_subset (n, m, SAFE_DEFLEXING)) {
7196 /* Unpack it */
7197         PACK_T *w;
7198         for (w = PACK (n); w != NO_PACK; FORWARD (w)) {
7199           add_mode_to_pack (&u, MOID (w), NO_TEXT, NODE (w));
7200         }
7201         mods++;
7202       } else {
7203         add_mode_to_pack (&u, MOID (v), NO_TEXT, NODE (v));
7204       }
7205     }
7206     PACK (m) = absorb_union_pack (u);
7207   } while (mods != 0);
7208   return (m);
7209 }
7210 
7211 /**
7212 @brief Make united mode, from mode that is a SERIES (..).
7213 @param m Series mode.
7214 @return Mode table entry.
7215 **/
7216 
7217 static MOID_T *
make_united_mode(MOID_T * m)7218 make_united_mode (MOID_T * m)
7219 {
7220   MOID_T *u;
7221   PACK_T *w;
7222   int mods;
7223   if (m == NO_MOID) {
7224     return (MODE (ERROR));
7225   } else if (ATTRIBUTE (m) != SERIES_MODE) {
7226     return (m);
7227   }
7228 /* Do not unite a single UNION */
7229   if (DIM (m) == 1 && IS (MOID (PACK (m)), UNION_SYMBOL)) {
7230     return (MOID (PACK (m)));
7231   }
7232 /* Straighten the series */
7233   absorb_series_union_pack (&m);
7234 /* Copy the series into a UNION */
7235   u = new_moid ();
7236   ATTRIBUTE (u) = UNION_SYMBOL;
7237   PACK (u) = NO_PACK;
7238   w = PACK (m);
7239   for (w = PACK (m); w != NO_PACK; FORWARD (w)) {
7240     add_mode_to_pack (&(PACK (u)), MOID (w), NO_TEXT, NODE (m));
7241   }
7242 /* Absorb and contract the new UNION */
7243   do {
7244     mods = 0;
7245     absorb_series_union_pack (&u);
7246     DIM (u) = count_pack_members (PACK (u));
7247     PACK (u) = absorb_union_pack (PACK (u));
7248     contract_union (u);
7249   } while (mods != 0);
7250 /* A UNION of one mode is that mode itself */
7251   if (DIM (u) == 1) {
7252     return (MOID (PACK (u)));
7253   } else {
7254     return (register_extra_mode (&TOP_MOID (&program), u));
7255   }
7256 }
7257 
7258 /**
7259 @brief Add row and its slices to chain, recursively.
7260 @param p Chain to insert into.
7261 @param dim Dimension.
7262 @param sub Mode of slice.
7263 @param n Node in syntax tree.
7264 @param derivate Whether derived, ie. not in the source.
7265 @return Pointer to entry.
7266 **/
7267 
7268 static MOID_T *
add_row(MOID_T ** p,int dim,MOID_T * sub,NODE_T * n,BOOL_T derivate)7269 add_row (MOID_T ** p, int dim, MOID_T * sub, NODE_T * n, BOOL_T derivate)
7270 {
7271   MOID_T *q = add_mode (p, ROW_SYMBOL, dim, n, sub, NO_PACK);
7272   DERIVATE (q) |= derivate;
7273   if (dim > 1) {
7274     SLICE (q) = add_row (&NEXT (q), dim - 1, sub, n, derivate);
7275   } else {
7276     SLICE (q) = sub;
7277   }
7278   return (q);
7279 }
7280 
7281 /**
7282 @brief Add a moid to a pack, maybe with a (field) name.
7283 @param p Pack.
7284 @param m Moid to add.
7285 @param text Field name.
7286 @param node Node in syntax tree.
7287 **/
7288 
7289 void
add_mode_to_pack(PACK_T ** p,MOID_T * m,char * text,NODE_T * node)7290 add_mode_to_pack (PACK_T ** p, MOID_T * m, char *text, NODE_T * node)
7291 {
7292   PACK_T *z = new_pack ();
7293   MOID (z) = m;
7294   TEXT (z) = text;
7295   NODE (z) = node;
7296   NEXT (z) = *p;
7297   PREVIOUS (z) = NO_PACK;
7298   if (NEXT (z) != NO_PACK) {
7299     PREVIOUS (NEXT (z)) = z;
7300   }
7301 /* Link in chain */
7302   *p = z;
7303 }
7304 
7305 /**
7306 @brief Add a moid to a pack, maybe with a (field) name.
7307 @param p Pack.
7308 @param m Moid to add.
7309 @param text Field name.
7310 @param node Node in syntax tree.
7311 **/
7312 
7313 void
add_mode_to_pack_end(PACK_T ** p,MOID_T * m,char * text,NODE_T * node)7314 add_mode_to_pack_end (PACK_T ** p, MOID_T * m, char *text, NODE_T * node)
7315 {
7316   PACK_T *z = new_pack ();
7317   MOID (z) = m;
7318   TEXT (z) = text;
7319   NODE (z) = node;
7320   NEXT (z) = NO_PACK;
7321   if (NEXT (z) != NO_PACK) {
7322     PREVIOUS (NEXT (z)) = z;
7323   }
7324 /* Link in chain */
7325   while ((*p) != NO_PACK) {
7326     p = &(NEXT (*p));
7327   }
7328   PREVIOUS (z) = (*p);
7329   (*p) = z;
7330 }
7331 
7332 /**
7333 @brief Absorb UNION members.
7334 @param m First MOID.
7335 **/
7336 
7337 static void
absorb_unions(MOID_T * m)7338 absorb_unions (MOID_T * m)
7339 {
7340 /*
7341 UNION (A, UNION (B, C)) = UNION (A, B, C) or
7342 UNION (A, UNION (A, B)) = UNION (A, B).
7343 */
7344   for (; m != NO_MOID; FORWARD (m)) {
7345     if (IS (m, UNION_SYMBOL)) {
7346       PACK (m) = absorb_union_pack (PACK (m));
7347     }
7348   }
7349 }
7350 
7351 
7352 /**
7353 @brief Contract UNIONs .
7354 @param m First MOID.
7355 **/
7356 
7357 static void
contract_unions(MOID_T * m)7358 contract_unions (MOID_T * m)
7359 {
7360 /* UNION (A, B, A) -> UNION (A, B) */
7361   for (; m != NO_MOID; FORWARD (m)) {
7362     if (IS (m, UNION_SYMBOL) && EQUIVALENT (m) == NO_MOID) {
7363       contract_union (m);
7364     }
7365   }
7366 }
7367 
7368 /***************************************************/
7369 /* Routines to collect MOIDs from the program text */
7370 /***************************************************/
7371 
7372 /**
7373 @brief Search standard mode in standard environ.
7374 @param sizety Sizety.
7375 @param indicant Node in syntax tree.
7376 @return Moid entry in standard environ.
7377 **/
7378 
7379 static MOID_T *
search_standard_mode(int sizety,NODE_T * indicant)7380 search_standard_mode (int sizety, NODE_T * indicant)
7381 {
7382   MOID_T *p = TOP_MOID (&program);
7383 /* Search standard mode */
7384   for (; p != NO_MOID; FORWARD (p)) {
7385     if (IS (p, STANDARD) && DIM (p) == sizety && NSYMBOL (NODE (p)) == NSYMBOL (indicant)) {
7386       return (p);
7387     }
7388   }
7389 /* Sanity check
7390   if (sizety == -2 || sizety == 2) {
7391     return (NO_MOID);
7392   }
7393 */
7394 /* Map onto greater precision */
7395   if (sizety < 0) {
7396     return (search_standard_mode (sizety + 1, indicant));
7397   } else if (sizety > 0) {
7398     return (search_standard_mode (sizety - 1, indicant));
7399   } else {
7400     return (NO_MOID);
7401   }
7402 }
7403 
7404 /**
7405 @brief Collect mode from STRUCT field.
7406 @param p Node in syntax tree.
7407 @param u Pack to insert to.
7408 **/
7409 
7410 static void
get_mode_from_struct_field(NODE_T * p,PACK_T ** u)7411 get_mode_from_struct_field (NODE_T * p, PACK_T ** u)
7412 {
7413   if (p != NO_NODE) {
7414     if (IS (p, IDENTIFIER)) {
7415       ATTRIBUTE (p) = FIELD_IDENTIFIER;
7416       (void) add_mode_to_pack (u, NO_MOID, NSYMBOL (p), p);
7417     } else if (IS (p, DECLARER)) {
7418       MOID_T *new_one = get_mode_from_declarer (p);
7419       PACK_T *t;
7420       get_mode_from_struct_field (NEXT (p), u);
7421       for (t = *u; t && MOID (t) == NO_MOID; FORWARD (t)) {
7422         MOID (t) = new_one;
7423         MOID (NODE (t)) = new_one;
7424       }
7425     } else {
7426       get_mode_from_struct_field (NEXT (p), u);
7427       get_mode_from_struct_field (SUB (p), u);
7428     }
7429   }
7430 }
7431 
7432 /**
7433 @brief Collect MODE from formal pack.
7434 @param p Node in syntax tree.
7435 @param u Pack to insert to.
7436 **/
7437 
7438 static void
get_mode_from_formal_pack(NODE_T * p,PACK_T ** u)7439 get_mode_from_formal_pack (NODE_T * p, PACK_T ** u)
7440 {
7441   if (p != NO_NODE) {
7442     if (IS (p, DECLARER)) {
7443       MOID_T *z;
7444       get_mode_from_formal_pack (NEXT (p), u);
7445       z = get_mode_from_declarer (p);
7446       (void) add_mode_to_pack (u, z, NO_TEXT, p);
7447     } else {
7448       get_mode_from_formal_pack (NEXT (p), u);
7449       get_mode_from_formal_pack (SUB (p), u);
7450     }
7451   }
7452 }
7453 
7454 /**
7455 @brief Collect MODE or VOID from formal UNION pack.
7456 @param p Node in syntax tree.
7457 @param u Pack to insert to.
7458 **/
7459 
7460 static void
get_mode_from_union_pack(NODE_T * p,PACK_T ** u)7461 get_mode_from_union_pack (NODE_T * p, PACK_T ** u)
7462 {
7463   if (p != NO_NODE) {
7464     if (IS (p, DECLARER) || IS (p, VOID_SYMBOL)) {
7465       MOID_T *z;
7466       get_mode_from_union_pack (NEXT (p), u);
7467       z = get_mode_from_declarer (p);
7468       (void) add_mode_to_pack (u, z, NO_TEXT, p);
7469     } else {
7470       get_mode_from_union_pack (NEXT (p), u);
7471       get_mode_from_union_pack (SUB (p), u);
7472     }
7473   }
7474 }
7475 
7476 /**
7477 @brief Collect mode from PROC, OP pack.
7478 @param p Node in syntax tree.
7479 @param u Pack to insert to.
7480 **/
7481 
7482 static void
get_mode_from_routine_pack(NODE_T * p,PACK_T ** u)7483 get_mode_from_routine_pack (NODE_T * p, PACK_T ** u)
7484 {
7485   if (p != NO_NODE) {
7486     if (IS (p, IDENTIFIER)) {
7487       (void) add_mode_to_pack (u, NO_MOID, NO_TEXT, p);
7488     } else if (IS (p, DECLARER)) {
7489       MOID_T *z = get_mode_from_declarer (p);
7490       PACK_T *t = *u;
7491       for (; t != NO_PACK && MOID (t) == NO_MOID; FORWARD (t)) {
7492         MOID (t) = z;
7493         MOID (NODE (t)) = z;
7494       }
7495       (void) add_mode_to_pack (u, z, NO_TEXT, p);
7496     } else {
7497       get_mode_from_routine_pack (NEXT (p), u);
7498       get_mode_from_routine_pack (SUB (p), u);
7499     }
7500   }
7501 }
7502 
7503 /**
7504 @brief Collect MODE from DECLARER.
7505 @param p Node in syntax tree.
7506 @return Mode table entry.
7507 **/
7508 
7509 static MOID_T *
get_mode_from_declarer(NODE_T * p)7510 get_mode_from_declarer (NODE_T * p)
7511 {
7512   if (p == NO_NODE) {
7513     return (NO_MOID);
7514   } else {
7515     if (IS (p, DECLARER)) {
7516       if (MOID (p) != NO_MOID) {
7517         return (MOID (p));
7518       } else {
7519         return (MOID (p) = get_mode_from_declarer (SUB (p)));
7520       }
7521     } else {
7522       if (IS (p, VOID_SYMBOL)) {
7523         MOID (p) = MODE (VOID);
7524         return (MOID (p));
7525       } else if (IS (p, LONGETY)) {
7526         if (whether (p, LONGETY, INDICANT, STOP)) {
7527           int k = count_sizety (SUB (p));
7528           MOID (p) = search_standard_mode (k, NEXT (p));
7529           return (MOID (p));
7530         } else {
7531           return (NO_MOID);
7532         }
7533       } else if (IS (p, SHORTETY)) {
7534         if (whether (p, SHORTETY, INDICANT, STOP)) {
7535           int k = count_sizety (SUB (p));
7536           MOID (p) = search_standard_mode (k, NEXT (p));
7537           return (MOID (p));
7538         } else {
7539           return (NO_MOID);
7540         }
7541       } else if (IS (p, INDICANT)) {
7542         MOID_T *q = search_standard_mode (0, p);
7543         if (q != NO_MOID) {
7544           MOID (p) = q;
7545         } else {
7546 /* Position of definition tells indicants apart */
7547           TAG_T *y = find_tag_global (TABLE (p), INDICANT, NSYMBOL (p));
7548           if (y == NO_TAG) {
7549             diagnostic_node (A68_ERROR, p, ERROR_UNDECLARED_TAG_2, NSYMBOL (p));
7550           } else {
7551             MOID (p) = add_mode (&TOP_MOID (&program), INDICANT, 0, NODE (y), NO_MOID, NO_PACK);
7552           }
7553         }
7554         return (MOID (p));
7555       } else if (IS (p, REF_SYMBOL)) {
7556         MOID_T *new_one = get_mode_from_declarer (NEXT (p));
7557         MOID (p) = add_mode (&TOP_MOID (&program), REF_SYMBOL, 0, p, new_one, NO_PACK);
7558         return (MOID (p));
7559       } else if (IS (p, FLEX_SYMBOL)) {
7560         MOID_T *new_one = get_mode_from_declarer (NEXT (p));
7561         MOID (p) = add_mode (&TOP_MOID (&program), FLEX_SYMBOL, 0, p, new_one, NO_PACK);
7562         SLICE (MOID (p)) = SLICE (new_one);
7563         return (MOID (p));
7564       } else if (IS (p, FORMAL_BOUNDS)) {
7565         MOID_T *new_one = get_mode_from_declarer (NEXT (p));
7566         MOID (p) = add_row (&TOP_MOID (&program), 1 + count_formal_bounds (SUB (p)), new_one, p, A68_FALSE);
7567         return (MOID (p));
7568       } else if (IS (p, BOUNDS)) {
7569         MOID_T *new_one = get_mode_from_declarer (NEXT (p));
7570         MOID (p) = add_row (&TOP_MOID (&program), count_bounds (SUB (p)), new_one, p, A68_FALSE);
7571         return (MOID (p));
7572       } else if (IS (p, STRUCT_SYMBOL)) {
7573         PACK_T *u = NO_PACK;
7574         get_mode_from_struct_field (NEXT (p), &u);
7575         MOID (p) = add_mode (&TOP_MOID (&program), STRUCT_SYMBOL, count_pack_members (u), p, NO_MOID, u);
7576         return (MOID (p));
7577       } else if (IS (p, UNION_SYMBOL)) {
7578         PACK_T *u = NO_PACK;
7579         get_mode_from_union_pack (NEXT (p), &u);
7580         MOID (p) = add_mode (&TOP_MOID (&program), UNION_SYMBOL, count_pack_members (u), p, NO_MOID, u);
7581         return (MOID (p));
7582       } else if (IS (p, PROC_SYMBOL)) {
7583         NODE_T *save = p;
7584         PACK_T *u = NO_PACK;
7585         MOID_T *new_one;
7586         if (IS (NEXT (p), FORMAL_DECLARERS)) {
7587           get_mode_from_formal_pack (SUB_NEXT (p), &u);
7588           FORWARD (p);
7589         }
7590         new_one = get_mode_from_declarer (NEXT (p));
7591         MOID (p) = add_mode (&TOP_MOID (&program), PROC_SYMBOL, count_pack_members (u), save, new_one, u);
7592         MOID (save) = MOID (p);
7593         return (MOID (p));
7594       } else {
7595         return (NO_MOID);
7596       }
7597     }
7598   }
7599 }
7600 
7601 /**
7602 @brief Collect MODEs from a routine-text header.
7603 @param p Node in syntax tree.
7604 @return Mode table entry.
7605 **/
7606 
7607 static MOID_T *
get_mode_from_routine_text(NODE_T * p)7608 get_mode_from_routine_text (NODE_T * p)
7609 {
7610   PACK_T *u = NO_PACK;
7611   MOID_T *n;
7612   NODE_T *q = p;
7613   if (IS (p, PARAMETER_PACK)) {
7614     get_mode_from_routine_pack (SUB (p), &u);
7615     FORWARD (p);
7616   }
7617   n = get_mode_from_declarer (p);
7618   return (add_mode (&TOP_MOID (&program), PROC_SYMBOL, count_pack_members (u), q, n, u));
7619 }
7620 
7621 /**
7622 @brief Collect modes from operator-plan.
7623 @param p Node in syntax tree.
7624 @return Mode table entry.
7625 **/
7626 
7627 static MOID_T *
get_mode_from_operator(NODE_T * p)7628 get_mode_from_operator (NODE_T * p)
7629 {
7630   PACK_T *u = NO_PACK;
7631   MOID_T *new_one;
7632   NODE_T *save = p;
7633   if (IS (NEXT (p), FORMAL_DECLARERS)) {
7634     get_mode_from_formal_pack (SUB_NEXT (p), &u);
7635     FORWARD (p);
7636   }
7637   new_one = get_mode_from_declarer (NEXT (p));
7638   MOID (p) = add_mode (&TOP_MOID (&program), PROC_SYMBOL, count_pack_members (u), save, new_one, u);
7639   return (MOID (p));
7640 }
7641 
7642 /**
7643 @brief Collect mode from denotation.
7644 @param p Node in syntax tree.
7645 @param sizety Size of denotation.
7646 @return Mode table entry.
7647 **/
7648 
7649 static void
get_mode_from_denotation(NODE_T * p,int sizety)7650 get_mode_from_denotation (NODE_T * p, int sizety)
7651 {
7652   if (p != NO_NODE) {
7653     if (IS (p, ROW_CHAR_DENOTATION)) {
7654       if (strlen (NSYMBOL (p)) == 1) {
7655         MOID (p) = MODE (CHAR);
7656       } else {
7657         MOID (p) = MODE (ROW_CHAR);
7658       }
7659     } else if (IS (p, TRUE_SYMBOL) || IS (p, FALSE_SYMBOL)) {
7660       MOID (p) = MODE (BOOL);
7661     } else if (IS (p, INT_DENOTATION)) {
7662       if (sizety == 0) {
7663         MOID (p) = MODE (INT);
7664       } else if (sizety == 1) {
7665         MOID (p) = MODE (LONG_INT);
7666       } else if (sizety == 2) {
7667         MOID (p) = MODE (LONGLONG_INT);
7668       } else {
7669         MOID (p) = (sizety > 0 ? MODE (LONGLONG_INT) : MODE (INT));
7670       }
7671     } else if (IS (p, REAL_DENOTATION)) {
7672       if (sizety == 0) {
7673         MOID (p) = MODE (REAL);
7674       } else if (sizety == 1) {
7675         MOID (p) = MODE (LONG_REAL);
7676       } else if (sizety == 2) {
7677         MOID (p) = MODE (LONGLONG_REAL);
7678       } else {
7679         MOID (p) = (sizety > 0 ? MODE (LONGLONG_REAL) : MODE (REAL));
7680       }
7681     } else if (IS (p, BITS_DENOTATION)) {
7682       if (sizety == 0) {
7683         MOID (p) = MODE (BITS);
7684       } else if (sizety == 1) {
7685         MOID (p) = MODE (LONG_BITS);
7686       } else if (sizety == 2) {
7687         MOID (p) = MODE (LONGLONG_BITS);
7688       } else {
7689         MOID (p) = (sizety > 0 ? MODE (LONGLONG_BITS) : MODE (BITS));
7690       }
7691     } else if (IS (p, LONGETY) || IS (p, SHORTETY)) {
7692       get_mode_from_denotation (NEXT (p), count_sizety (SUB (p)));
7693       MOID (p) = MOID (NEXT (p));
7694     } else if (IS (p, EMPTY_SYMBOL)) {
7695       MOID (p) = MODE (VOID);
7696     }
7697   }
7698 }
7699 
7700 /**
7701 @brief Collect modes from the syntax tree.
7702 @param p Node in syntax tree.
7703 @param attribute
7704 **/
7705 
7706 static void
get_modes_from_tree(NODE_T * p,int attribute)7707 get_modes_from_tree (NODE_T * p, int attribute)
7708 {
7709   NODE_T *q;
7710   for (q = p; q != NO_NODE; FORWARD (q)) {
7711     if (IS (q, VOID_SYMBOL)) {
7712       MOID (q) = MODE (VOID);
7713     } else if (IS (q, DECLARER)) {
7714       if (attribute == VARIABLE_DECLARATION) {
7715         MOID_T *new_one = get_mode_from_declarer (q);
7716         MOID (q) = add_mode (&TOP_MOID (&program), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK);
7717       } else {
7718         MOID (q) = get_mode_from_declarer (q);
7719       }
7720     } else if (IS (q, ROUTINE_TEXT)) {
7721       MOID (q) = get_mode_from_routine_text (SUB (q));
7722     } else if (IS (q, OPERATOR_PLAN)) {
7723       MOID (q) = get_mode_from_operator (SUB (q));
7724     } else if (is_one_of (q, LOC_SYMBOL, HEAP_SYMBOL, NEW_SYMBOL, STOP)) {
7725       if (attribute == GENERATOR) {
7726         MOID_T *new_one = get_mode_from_declarer (NEXT (q));
7727         MOID (NEXT (q)) = new_one;
7728         MOID (q) = add_mode (&TOP_MOID (&program), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK);
7729       }
7730     } else {
7731       if (attribute == DENOTATION) {
7732         get_mode_from_denotation (q, 0);
7733       }
7734     }
7735   }
7736   if (attribute != DENOTATION) {
7737     for (q = p; q != NO_NODE; FORWARD (q)) {
7738       if (SUB (q) != NO_NODE) {
7739         get_modes_from_tree (SUB (q), ATTRIBUTE (q));
7740       }
7741     }
7742   }
7743 }
7744 
7745 /**
7746 @brief Collect modes from proc variables.
7747 @param p Node in syntax tree.
7748 **/
7749 
7750 static void
get_mode_from_proc_variables(NODE_T * p)7751 get_mode_from_proc_variables (NODE_T * p)
7752 {
7753   if (p != NO_NODE) {
7754     if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
7755       get_mode_from_proc_variables (SUB (p));
7756       get_mode_from_proc_variables (NEXT (p));
7757     } else if (IS (p, QUALIFIER) || IS (p, PROC_SYMBOL) || IS (p, COMMA_SYMBOL)) {
7758       get_mode_from_proc_variables (NEXT (p));
7759     } else if (IS (p, DEFINING_IDENTIFIER)) {
7760       MOID_T *new_one = MOID (NEXT_NEXT (p));
7761       MOID (p) = add_mode (&TOP_MOID (&program), REF_SYMBOL, 0, p, new_one, NO_PACK);
7762     }
7763   }
7764 }
7765 
7766 /**
7767 @brief Collect modes from proc variable declarations.
7768 @param p Node in syntax tree.
7769 **/
7770 
7771 static void
get_mode_from_proc_var_declarations_tree(NODE_T * p)7772 get_mode_from_proc_var_declarations_tree (NODE_T * p)
7773 {
7774   for (; p != NO_NODE; FORWARD (p)) {
7775     get_mode_from_proc_var_declarations_tree (SUB (p));
7776     if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
7777       get_mode_from_proc_variables (p);
7778     }
7779   }
7780 }
7781 
7782 /**********************************/
7783 /* Various routines to test modes */
7784 /**********************************/
7785 
7786 /**
7787 @brief Whether a mode declaration refers to self or relates to void.
7788 @param def Entry of indicant in mode table, NO_MOID if z is an applied mode.
7789 @param z Mode to check.
7790 @param yin Whether shields YIN.
7791 @param yang Whether shields YANG.
7792 @param video Whether shields VOID .
7793 @return See brief description.
7794 **/
7795 
7796 static BOOL_T
is_well_formed(MOID_T * def,MOID_T * z,BOOL_T yin,BOOL_T yang,BOOL_T video)7797 is_well_formed (MOID_T * def, MOID_T * z, BOOL_T yin, BOOL_T yang, BOOL_T video)
7798 {
7799   if (z == NO_MOID) {
7800     return (A68_FALSE);
7801   } else if (yin && yang) {
7802     return (z == MODE (VOID) ? video : A68_TRUE);
7803   } else if (z == MODE (VOID)) {
7804     return (video);
7805   } else if (IS (z, STANDARD)) {
7806     return (A68_TRUE);
7807   } else if (IS (z, INDICANT)) {
7808     if (def == NO_MOID) {
7809 /* Check an applied indicant for relation to VOID */
7810       while (z != NO_MOID) {
7811         z = EQUIVALENT (z);
7812       }
7813       if (z == MODE (VOID)) {
7814         return (video);
7815       } else {
7816         return (A68_TRUE);
7817       }
7818     } else {
7819       if (z == def || USE (z)) {
7820         return (yin && yang);
7821       } else {
7822         BOOL_T wwf;
7823         USE (z) = A68_TRUE;
7824         wwf = is_well_formed (def, EQUIVALENT (z), yin, yang, video);
7825         USE (z) = A68_FALSE;
7826         return (wwf);
7827       }
7828     }
7829   } else if (IS (z, REF_SYMBOL)) {
7830     return (is_well_formed (def, SUB (z), A68_TRUE, yang, A68_FALSE));
7831   } else if (IS (z, PROC_SYMBOL)) {
7832     return (PACK (z) != NO_PACK ? A68_TRUE : is_well_formed (def, SUB (z), A68_TRUE, yang, A68_TRUE));
7833   } else if (IS (z, ROW_SYMBOL)) {
7834     return (is_well_formed (def, SUB (z), yin, yang, A68_FALSE));
7835   } else if (IS (z, FLEX_SYMBOL)) {
7836     return (is_well_formed (def, SUB (z), yin, yang, A68_FALSE));
7837   } else if (IS (z, STRUCT_SYMBOL)) {
7838     PACK_T *s = PACK (z);
7839     for (; s != NO_PACK; FORWARD (s)) {
7840       if (!is_well_formed (def, MOID (s), yin, A68_TRUE, A68_FALSE)) {
7841         return (A68_FALSE);
7842       }
7843     }
7844     return (A68_TRUE);
7845   } else if (IS (z, UNION_SYMBOL)) {
7846     PACK_T *s = PACK (z);
7847     for (; s != NO_PACK; FORWARD (s)) {
7848       if (!is_well_formed (def, MOID (s), yin, yang, A68_TRUE)) {
7849         return (A68_FALSE);
7850       }
7851     }
7852     return (A68_TRUE);
7853   } else {
7854     return (A68_FALSE);
7855   }
7856 }
7857 
7858 /**
7859 @brief Replace a mode by its equivalent mode (walk chain).
7860 @param q Mode to track.
7861 **/
7862 
7863 static void
resolve_eq_members(MOID_T * q)7864 resolve_eq_members (MOID_T * q)
7865 {
7866   PACK_T *p;
7867   resolve_equivalent (&SUB (q));
7868   resolve_equivalent (&DEFLEXED (q));
7869   resolve_equivalent (&MULTIPLE (q));
7870   resolve_equivalent (&NAME (q));
7871   resolve_equivalent (&SLICE (q));
7872   resolve_equivalent (&TRIM (q));
7873   resolve_equivalent (&ROWED (q));
7874   for (p = PACK (q); p != NO_PACK; FORWARD (p)) {
7875     resolve_equivalent (&MOID (p));
7876   }
7877 }
7878 
7879 /**
7880 @brief Track equivalent tags.
7881 @param z Tag to track.
7882 **/
7883 
7884 static void
resolve_eq_tags(TAG_T * z)7885 resolve_eq_tags (TAG_T * z)
7886 {
7887   for (; z != NO_TAG; FORWARD (z)) {
7888     if (MOID (z) != NO_MOID) {
7889       resolve_equivalent (&MOID (z));
7890     }
7891   }
7892 }
7893 
7894 /**
7895 @brief Bind modes in syntax tree.
7896 @param p Node in syntax tree.
7897 **/
7898 
7899 static void
bind_modes(NODE_T * p)7900 bind_modes (NODE_T * p)
7901 {
7902   for (; p != NO_NODE; FORWARD (p)) {
7903     resolve_equivalent (&MOID (p));
7904     if (SUB (p) != NO_NODE && is_new_lexical_level (p)) {
7905       TABLE_T *s = TABLE (SUB (p));
7906       TAG_T *z = INDICANTS (s);
7907       for (; z != NO_TAG; FORWARD (z)) {
7908         if (NODE (z) != NO_NODE) {
7909           resolve_equivalent (&MOID (NEXT_NEXT (NODE (z))));
7910           MOID (z) = MOID (NEXT_NEXT (NODE (z)));
7911           MOID (NODE (z)) = MOID (z);
7912         }
7913       }
7914     }
7915     bind_modes (SUB (p));
7916   }
7917 }
7918 
7919 /*
7920 Routines for calculating subordinates for selections, for instance selection
7921 from REF STRUCT (A) yields REF A fields and selection from [] STRUCT (A) yields
7922 [] A fields.
7923 */
7924 
7925 /**
7926 @brief Make name pack.
7927 @param src Source pack.
7928 @param dst Destination pack with REF modes.
7929 @param p Chain to insert new modes into.
7930 **/
7931 
7932 static void
make_name_pack(PACK_T * src,PACK_T ** dst,MOID_T ** p)7933 make_name_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p)
7934 {
7935   if (src != NO_PACK) {
7936     MOID_T *z;
7937     make_name_pack (NEXT (src), dst, p);
7938     z = add_mode (p, REF_SYMBOL, 0, NO_NODE, MOID (src), NO_PACK);
7939     (void) add_mode_to_pack (dst, z, TEXT (src), NODE (src));
7940   }
7941 }
7942 
7943 /**
7944 @brief Make flex multiple row pack.
7945 @param src Source pack.
7946 @param dst Destination pack with REF modes.
7947 @param p Chain to insert new modes into.
7948 @param dim Dimension.
7949 **/
7950 
7951 static void
make_flex_multiple_row_pack(PACK_T * src,PACK_T ** dst,MOID_T ** p,int dim)7952 make_flex_multiple_row_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p, int dim)
7953 {
7954   if (src != NO_PACK) {
7955     MOID_T *z;
7956     make_flex_multiple_row_pack (NEXT (src), dst, p, dim);
7957     z = add_row (p, dim, MOID (src), NO_NODE, A68_FALSE);
7958     z = add_mode (p, FLEX_SYMBOL, 0, NO_NODE, z, NO_PACK);
7959     (void) add_mode_to_pack (dst, z, TEXT (src), NODE (src));
7960   }
7961 }
7962 
7963 /**
7964 @brief Make name struct.
7965 @param m Structured mode.
7966 @param p Chain to insert new modes into.
7967 @return Mode table entry.
7968 **/
7969 
7970 static MOID_T *
make_name_struct(MOID_T * m,MOID_T ** p)7971 make_name_struct (MOID_T * m, MOID_T ** p)
7972 {
7973   PACK_T *u = NO_PACK;
7974   make_name_pack (PACK (m), &u, p);
7975   return (add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u));
7976 }
7977 
7978 /**
7979 @brief Make name row.
7980 @param m Rowed mode.
7981 @param p Chain to insert new modes into.
7982 @return Mode table entry.
7983 **/
7984 
7985 static MOID_T *
make_name_row(MOID_T * m,MOID_T ** p)7986 make_name_row (MOID_T * m, MOID_T ** p)
7987 {
7988   if (SLICE (m) != NO_MOID) {
7989     return (add_mode (p, REF_SYMBOL, 0, NO_NODE, SLICE (m), NO_PACK));
7990   } else if (SUB (m) != NO_MOID) {
7991     return (add_mode (p, REF_SYMBOL, 0, NO_NODE, SUB (m), NO_PACK));
7992   } else {
7993     return (NO_MOID);           /* weird, FLEX INT or so ... */
7994   }
7995 }
7996 
7997 /**
7998 @brief Make multiple row pack.
7999 @param src Source pack.
8000 @param dst Destination pack with REF modes.
8001 @param p Chain to insert new modes into.
8002 @param dim Dimension.
8003 **/
8004 
8005 static void
make_multiple_row_pack(PACK_T * src,PACK_T ** dst,MOID_T ** p,int dim)8006 make_multiple_row_pack (PACK_T * src, PACK_T ** dst, MOID_T ** p, int dim)
8007 {
8008   if (src != NO_PACK) {
8009     make_multiple_row_pack (NEXT (src), dst, p, dim);
8010     (void) add_mode_to_pack (dst, add_row (p, dim, MOID (src), NO_NODE, A68_FALSE), TEXT (src), NODE (src));
8011   }
8012 }
8013 
8014 /**
8015 @brief Make flex multiple struct.
8016 @param m Structured mode.
8017 @param p Chain to insert new modes into.
8018 @param dim Dimension.
8019 @return Mode table entry.
8020 **/
8021 
8022 static MOID_T *
make_flex_multiple_struct(MOID_T * m,MOID_T ** p,int dim)8023 make_flex_multiple_struct (MOID_T * m, MOID_T ** p, int dim)
8024 {
8025   PACK_T *u = NO_PACK;
8026   make_flex_multiple_row_pack (PACK (m), &u, p, dim);
8027   return (add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u));
8028 }
8029 
8030 /**
8031 @brief Make multiple struct.
8032 @param m Structured mode.
8033 @param p Chain to insert new modes into.
8034 @param dim Dimension.
8035 @return Mode table entry.
8036 **/
8037 
8038 static MOID_T *
make_multiple_struct(MOID_T * m,MOID_T ** p,int dim)8039 make_multiple_struct (MOID_T * m, MOID_T ** p, int dim)
8040 {
8041   PACK_T *u = NO_PACK;
8042   make_multiple_row_pack (PACK (m), &u, p, dim);
8043   return (add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u));
8044 }
8045 
8046 /**
8047 @brief Whether mode has row.
8048 @param m Mode under test.
8049 @return See brief description.
8050 **/
8051 
8052 static BOOL_T
is_mode_has_row(MOID_T * m)8053 is_mode_has_row (MOID_T * m)
8054 {
8055   if (IS (m, STRUCT_SYMBOL) || IS (m, UNION_SYMBOL)) {
8056     BOOL_T k = A68_FALSE;
8057     PACK_T *p = PACK (m);
8058     for (; p != NO_PACK && k == A68_FALSE; FORWARD (p)) {
8059       HAS_ROWS (MOID (p)) = is_mode_has_row (MOID (p));
8060       k |= (HAS_ROWS (MOID (p)));
8061     }
8062     return (k);
8063   } else {
8064     return ((BOOL_T) (HAS_ROWS (m) || IS (m, ROW_SYMBOL) || IS (m, FLEX_SYMBOL)));
8065   }
8066 }
8067 
8068 /**
8069 @brief Compute derived modes.
8070 @param mod Module.
8071 **/
8072 
8073 static void
compute_derived_modes(MODULE_T * mod)8074 compute_derived_modes (MODULE_T * mod)
8075 {
8076   MOID_T *z;
8077   int k, len = 0, nlen = 1;
8078 /* UNION things */
8079   absorb_unions (TOP_MOID (mod));
8080   contract_unions (TOP_MOID (mod));
8081 /* The for-statement below prevents an endless loop */
8082   for (k = 1; k <= 10 && len != nlen; k++) {
8083 /* Make deflexed modes */
8084     for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8085       if (SUB (z) != NO_MOID) {
8086         if (IS_REF_FLEX (z) && DEFLEXED (SUB_SUB (z)) != NO_MOID) {
8087           DEFLEXED (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB_SUB (z)), NO_PACK);
8088         } else if (IS (z, REF_SYMBOL) && DEFLEXED (SUB (z)) != NO_MOID) {
8089           DEFLEXED (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB (z)), NO_PACK);
8090         } else if (IS (z, ROW_SYMBOL) && DEFLEXED (SUB (z)) != NO_MOID) {
8091           DEFLEXED (z) = add_mode (&TOP_MOID (mod), ROW_SYMBOL, DIM (z), NODE (z), DEFLEXED (SUB (z)), NO_PACK);
8092         } else if (IS (z, FLEX_SYMBOL) && DEFLEXED (SUB (z)) != NO_MOID) {
8093           DEFLEXED (z) = DEFLEXED (SUB (z));
8094         } else if (IS (z, FLEX_SYMBOL)) {
8095           DEFLEXED (z) = SUB (z);
8096         } else {
8097           DEFLEXED (z) = z;
8098         }
8099       }
8100     }
8101 /* Derived modes for stowed modes */
8102     for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8103       if (NAME (z) == NO_MOID && IS (z, REF_SYMBOL)) {
8104         if (IS (SUB (z), STRUCT_SYMBOL)) {
8105           NAME (z) = make_name_struct (SUB (z), &TOP_MOID (mod));
8106         } else if (IS (SUB (z), ROW_SYMBOL)) {
8107           NAME (z) = make_name_row (SUB (z), &TOP_MOID (mod));
8108         } else if (IS (SUB (z), FLEX_SYMBOL) && SUB_SUB (z) != NO_MOID) {
8109           NAME (z) = make_name_row (SUB_SUB (z), &TOP_MOID (mod));
8110         }
8111       }
8112       if (MULTIPLE (z) != NO_MOID) {
8113         ;
8114       } else if (IS (z, REF_SYMBOL)) {
8115         if (MULTIPLE (SUB (z)) != NO_MOID) {
8116           MULTIPLE (z) = make_name_struct (MULTIPLE (SUB (z)), &TOP_MOID (mod));
8117         }
8118       } else if (IS (z, ROW_SYMBOL)) {
8119         if (IS (SUB (z), STRUCT_SYMBOL)) {
8120           MULTIPLE (z) = make_multiple_struct (SUB (z), &TOP_MOID (mod), DIM (z));
8121         }
8122       }
8123     }
8124     for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8125       if (TRIM (z) == NO_MOID && IS (z, FLEX_SYMBOL)) {
8126         TRIM (z) = SUB (z);
8127       }
8128       if (TRIM (z) == NO_MOID && IS_REF_FLEX (z)) {
8129         TRIM (z) = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), SUB_SUB (z), NO_PACK);
8130       }
8131     }
8132 /* Fill out stuff for rows, f.i. inverse relations */
8133     for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8134       if (IS (z, ROW_SYMBOL) && DIM (z) > 0 && SUB (z) != NO_MOID && !DERIVATE (z)) {
8135         (void) add_row (&TOP_MOID (mod), DIM (z) + 1, SUB (z), NODE (z), A68_TRUE);
8136       } else if (IS (z, REF_SYMBOL) && IS (SUB (z), ROW_SYMBOL) && !DERIVATE (SUB (z))) {
8137         MOID_T *x = add_row (&TOP_MOID (mod), DIM (SUB (z)) + 1, SUB_SUB (z), NODE (SUB (z)), A68_TRUE);
8138         MOID_T *y = add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), x, NO_PACK);
8139         NAME (y) = z;
8140       }
8141     }
8142     for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8143       if (IS (z, ROW_SYMBOL) && SLICE (z) != NO_MOID) {
8144         ROWED (SLICE (z)) = z;
8145       }
8146       if (IS (z, REF_SYMBOL)) {
8147         MOID_T *y = SUB (z);
8148         if (SLICE (y) != NO_MOID && IS (SLICE (y), ROW_SYMBOL) && NAME (z) != NO_MOID) {
8149           ROWED (NAME (z)) = z;
8150         }
8151       }
8152     }
8153     bind_modes (TOP_NODE (mod));
8154     for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8155       if (IS (z, INDICANT) && NODE (z) != NO_NODE) {
8156         EQUIVALENT (z) = MOID (NODE (z));
8157       }
8158     }
8159     for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8160       resolve_eq_members (z);
8161     }
8162     resolve_eq_tags (INDICANTS (a68g_standenv));
8163     resolve_eq_tags (IDENTIFIERS (a68g_standenv));
8164     resolve_eq_tags (OPERATORS (a68g_standenv));
8165     resolve_equivalent (&MODE (STRING));
8166     resolve_equivalent (&MODE (COMPLEX));
8167     resolve_equivalent (&MODE (COMPL));
8168     resolve_equivalent (&MODE (LONG_COMPLEX));
8169     resolve_equivalent (&MODE (LONG_COMPL));
8170     resolve_equivalent (&MODE (LONGLONG_COMPLEX));
8171     resolve_equivalent (&MODE (LONGLONG_COMPL));
8172     resolve_equivalent (&MODE (SEMA));
8173     resolve_equivalent (&MODE (PIPE));
8174 /* UNION members could be resolved */
8175     absorb_unions (TOP_MOID (mod));
8176     contract_unions (TOP_MOID (mod));
8177 /* FLEX INDICANT could be resolved */
8178     for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8179       if (IS (z, FLEX_SYMBOL) && SUB (z) != NO_MOID) {
8180         if (SUB_SUB (z) != NO_MOID && IS (SUB_SUB (z), STRUCT_SYMBOL)) {
8181           MULTIPLE (z) = make_flex_multiple_struct (SUB_SUB (z), &TOP_MOID (mod), DIM (SUB (z)));
8182         }
8183       }
8184     }
8185 /* See what new known modes we have generated by resolving. */
8186     for (z = TOP_MOID (mod); z != STANDENV_MOID (&program); FORWARD (z)) {
8187       MOID_T *v;
8188       for (v = NEXT (z); v != NO_MOID; FORWARD (v)) {
8189         if (prove_moid_equivalence (z, v)) {
8190           EQUIVALENT (z) = v;
8191           EQUIVALENT (v) = NO_MOID;
8192         }
8193       }
8194     }
8195 /* Count the modes to check self consistency */
8196     len = nlen;
8197     for (nlen = 0, z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8198       nlen++;
8199     }
8200   }
8201   ABEND (MODE (STRING) != MODE (FLEX_ROW_CHAR), "equivalencing is broken", NO_TEXT);
8202 /* Find out what modes contain rows */
8203   for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8204     HAS_ROWS (z) = is_mode_has_row (z);
8205   }
8206 /* Check flexible modes */
8207   for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8208     if (IS (z, FLEX_SYMBOL) && ISNT (SUB (z), ROW_SYMBOL)) {
8209       diagnostic_node (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
8210     }
8211   }
8212 /* Check on fields in structured modes f.i. STRUCT (REAL x, INT n, REAL x) is wrong */
8213   for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8214     if (IS (z, STRUCT_SYMBOL) && EQUIVALENT (z) == NO_MOID) {
8215       PACK_T *s = PACK (z);
8216       for (; s != NO_PACK; FORWARD (s)) {
8217         PACK_T *t = NEXT (s);
8218         BOOL_T x = A68_TRUE;
8219         for (t = NEXT (s); t != NO_PACK && x; FORWARD (t)) {
8220           if (TEXT (s) == TEXT (t)) {
8221             diagnostic_node (A68_ERROR, NODE (z), ERROR_MULTIPLE_FIELD);
8222             while (NEXT (s) != NO_PACK && TEXT (NEXT (s)) == TEXT (t)) {
8223               FORWARD (s);
8224             }
8225             x = A68_FALSE;
8226           }
8227         }
8228       }
8229     }
8230   }
8231 /* Various union test */
8232   for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8233     if (IS (z, UNION_SYMBOL) && EQUIVALENT (z) == NO_MOID) {
8234       PACK_T *s = PACK (z);
8235 /* Discard unions with one member */
8236       if (count_pack_members (s) == 1) {
8237         diagnostic_node (A68_ERROR, NODE (z), ERROR_COMPONENT_NUMBER, z);
8238       }
8239 /* Discard incestuous unions with firmly related modes */
8240       for (; s != NO_PACK; FORWARD (s)) {
8241         PACK_T *t;
8242         for (t = NEXT (s); t != NO_PACK; FORWARD (t)) {
8243           if (MOID (t) != MOID (s)) {
8244             if (is_firm (MOID (s), MOID (t))) {
8245               diagnostic_node (A68_ERROR, NODE (z), ERROR_COMPONENT_RELATED, z);
8246             }
8247           }
8248         }
8249       }
8250 /* Discard incestuous unions with firmly related subsets */
8251       for (s = PACK (z); s != NO_PACK; FORWARD (s)) {
8252         MOID_T *n = depref_completely (MOID (s));
8253         if (IS (n, UNION_SYMBOL) && is_subset (n, z, NO_DEFLEXING)) {
8254           diagnostic_node (A68_ERROR, NODE (z), ERROR_SUBSET_RELATED, z, n);
8255         }
8256       }
8257     }
8258   }
8259 /* Wrap up and exit */
8260 /* Overwrite old equivalent modes now */
8261 /*
8262   for (u = &TOP_MOID (mod); (*u) != NO_MOID; u = & NEXT (*u)) {
8263     while ((*u) != NO_MOID && EQUIVALENT (*u) != NO_MOID) {
8264       (*u) = NEXT (*u);
8265     }
8266   }
8267 */
8268   free_postulate_list (top_postulate, NO_POSTULATE);
8269   top_postulate = NO_POSTULATE;
8270 }
8271 
8272 /**
8273 @brief Make list of all modes in the program.
8274 @param mod Module to list modes of.
8275 **/
8276 
8277 void
make_moid_list(MODULE_T * mod)8278 make_moid_list (MODULE_T * mod)
8279 {
8280   MOID_T *z;
8281   BOOL_T cont = A68_TRUE;
8282 /* Collect modes from the syntax tree */
8283   reset_moid_tree (TOP_NODE (mod));
8284   get_modes_from_tree (TOP_NODE (mod), STOP);
8285   get_mode_from_proc_var_declarations_tree (TOP_NODE (mod));
8286 /* Connect indicants to their declarers */
8287   for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8288     if (IS (z, INDICANT)) {
8289       NODE_T *u = NODE (z);
8290       ABEND (NEXT (u) == NO_NODE, "error in mode table", NO_TEXT);
8291       ABEND (NEXT_NEXT (u) == NO_NODE, "error in mode table", NO_TEXT);
8292       ABEND (MOID (NEXT_NEXT (u)) == NO_MOID, "error in mode table", NO_TEXT);
8293       EQUIVALENT (z) = MOID (NEXT_NEXT (u));
8294     }
8295   }
8296 /* Checks on wrong declarations */
8297   for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8298     USE (z) = A68_FALSE;
8299   }
8300   for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8301     if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) {
8302       if (!is_well_formed (z, EQUIVALENT (z), A68_FALSE, A68_FALSE, A68_TRUE)) {
8303         diagnostic_node (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
8304         cont = A68_FALSE;
8305       }
8306     }
8307   }
8308   for (z = TOP_MOID (mod); cont && z != NO_MOID; FORWARD (z)) {
8309     if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) {
8310       ;
8311     } else if (NODE (z) != NO_NODE) {
8312       if (!is_well_formed (NO_MOID, z, A68_FALSE, A68_FALSE, A68_TRUE)) {
8313         diagnostic_node (A68_ERROR, NODE (z), ERROR_NOT_WELL_FORMED, z);
8314       }
8315     }
8316   }
8317   for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) {
8318     ABEND (USE (z), ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
8319   }
8320   if (ERROR_COUNT (mod) != 0) {
8321     return;
8322   }
8323   compute_derived_modes (mod);
8324   init_postulates ();
8325 }
8326 
8327 /****************************************/
8328 /* Symbol table handling, managing TAGS */
8329 /****************************************/
8330 
8331 /**
8332 @brief Set level for procedures.
8333 @param p Node in syntax tree.
8334 @param n Proc level number.
8335 **/
8336 
8337 void
set_proc_level(NODE_T * p,int n)8338 set_proc_level (NODE_T * p, int n)
8339 {
8340   for (; p != NO_NODE; FORWARD (p)) {
8341     PROCEDURE_LEVEL (INFO (p)) = n;
8342     if (IS (p, ROUTINE_TEXT)) {
8343       set_proc_level (SUB (p), n + 1);
8344     } else {
8345       set_proc_level (SUB (p), n);
8346     }
8347   }
8348 }
8349 
8350 /**
8351 @brief Set nests for diagnostics.
8352 @param p Node in syntax tree.
8353 @param s Start of enclosing nest.
8354 **/
8355 
8356 void
set_nest(NODE_T * p,NODE_T * s)8357 set_nest (NODE_T * p, NODE_T * s)
8358 {
8359   for (; p != NO_NODE; FORWARD (p)) {
8360     NEST (p) = s;
8361     if (IS (p, PARTICULAR_PROGRAM)) {
8362       set_nest (SUB (p), p);
8363     } else if (IS (p, CLOSED_CLAUSE) && LINE_NUMBER (p) != 0) {
8364       set_nest (SUB (p), p);
8365     } else if (IS (p, COLLATERAL_CLAUSE) && LINE_NUMBER (p) != 0) {
8366       set_nest (SUB (p), p);
8367     } else if (IS (p, CONDITIONAL_CLAUSE) && LINE_NUMBER (p) != 0) {
8368       set_nest (SUB (p), p);
8369     } else if (IS (p, CASE_CLAUSE) && LINE_NUMBER (p) != 0) {
8370       set_nest (SUB (p), p);
8371     } else if (IS (p, CONFORMITY_CLAUSE) && LINE_NUMBER (p) != 0) {
8372       set_nest (SUB (p), p);
8373     } else if (IS (p, LOOP_CLAUSE) && LINE_NUMBER (p) != 0) {
8374       set_nest (SUB (p), p);
8375     } else {
8376       set_nest (SUB (p), s);
8377     }
8378   }
8379 }
8380 
8381 /* Routines that work with tags and symbol tables */
8382 
8383 static void tax_tags (NODE_T *);
8384 static void tax_specifier_list (NODE_T *);
8385 static void tax_parameter_list (NODE_T *);
8386 static void tax_format_texts (NODE_T *);
8387 
8388 /**
8389 @brief Find a tag, searching symbol tables towards the root.
8390 @param table Symbol table to search.
8391 @param name Name of tag.
8392 @return Type of tag, identifier or label or ....
8393 **/
8394 
8395 int
first_tag_global(TABLE_T * table,char * name)8396 first_tag_global (TABLE_T * table, char *name)
8397 {
8398   if (table != NO_TABLE) {
8399     TAG_T *s = NO_TAG;
8400     for (s = IDENTIFIERS (table); s != NO_TAG; FORWARD (s)) {
8401       if (NSYMBOL (NODE (s)) == name) {
8402         return (IDENTIFIER);
8403       }
8404     }
8405     for (s = INDICANTS (table); s != NO_TAG; FORWARD (s)) {
8406       if (NSYMBOL (NODE (s)) == name) {
8407         return (INDICANT);
8408       }
8409     }
8410     for (s = LABELS (table); s != NO_TAG; FORWARD (s)) {
8411       if (NSYMBOL (NODE (s)) == name) {
8412         return (LABEL);
8413       }
8414     }
8415     for (s = OPERATORS (table); s != NO_TAG; FORWARD (s)) {
8416       if (NSYMBOL (NODE (s)) == name) {
8417         return (OP_SYMBOL);
8418       }
8419     }
8420     for (s = PRIO (table); s != NO_TAG; FORWARD (s)) {
8421       if (NSYMBOL (NODE (s)) == name) {
8422         return (PRIO_SYMBOL);
8423       }
8424     }
8425     return (first_tag_global (PREVIOUS (table), name));
8426   } else {
8427     return (STOP);
8428   }
8429 }
8430 
8431 #define PORTCHECK_TAX(p, q) {\
8432   if (q == A68_FALSE) {\
8433     diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, p, WARNING_TAG_NOT_PORTABLE);\
8434   }}
8435 
8436 /**
8437 @brief Check portability of sub tree.
8438 @param p Node in syntax tree.
8439 **/
8440 
8441 void
portcheck(NODE_T * p)8442 portcheck (NODE_T * p)
8443 {
8444   for (; p != NO_NODE; FORWARD (p)) {
8445     portcheck (SUB (p));
8446     if (OPTION_PORTCHECK (&program)) {
8447       if (IS (p, INDICANT) && MOID (p) != NO_MOID) {
8448         PORTCHECK_TAX (p, PORTABLE (MOID (p)));
8449         PORTABLE (MOID (p)) = A68_TRUE;
8450       } else if (IS (p, IDENTIFIER)) {
8451         PORTCHECK_TAX (p, PORTABLE (TAX (p)));
8452         PORTABLE (TAX (p)) = A68_TRUE;
8453       } else if (IS (p, OPERATOR)) {
8454         PORTCHECK_TAX (p, PORTABLE (TAX (p)));
8455         PORTABLE (TAX (p)) = A68_TRUE;
8456       } else if (IS (p, ASSERTION)) {
8457         diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, p, WARNING_TAG_NOT_PORTABLE);
8458       }
8459     }
8460   }
8461 }
8462 
8463 /**
8464 @brief Whether routine can be "lengthety-mapped".
8465 @param z Name of routine.
8466 @return See brief description.
8467 **/
8468 
8469 static BOOL_T
is_mappable_routine(char * z)8470 is_mappable_routine (char *z)
8471 {
8472 #define ACCEPT(u, v) {\
8473   if (strlen (u) >= strlen (v)) {\
8474     if (strcmp (&u[strlen (u) - strlen (v)], v) == 0) {\
8475       return (A68_TRUE);\
8476   }}}
8477 /* Math routines */
8478   ACCEPT (z, "arccos");
8479   ACCEPT (z, "arcsin");
8480   ACCEPT (z, "arctan");
8481   ACCEPT (z, "cbrt");
8482   ACCEPT (z, "cos");
8483   ACCEPT (z, "curt");
8484   ACCEPT (z, "exp");
8485   ACCEPT (z, "ln");
8486   ACCEPT (z, "log");
8487   ACCEPT (z, "pi");
8488   ACCEPT (z, "sin");
8489   ACCEPT (z, "sqrt");
8490   ACCEPT (z, "tan");
8491 /* Random generator */
8492   ACCEPT (z, "nextrandom");
8493   ACCEPT (z, "random");
8494 /* BITS */
8495   ACCEPT (z, "bitspack");
8496 /* Enquiries */
8497   ACCEPT (z, "maxint");
8498   ACCEPT (z, "intwidth");
8499   ACCEPT (z, "maxreal");
8500   ACCEPT (z, "realwidth");
8501   ACCEPT (z, "expwidth");
8502   ACCEPT (z, "maxbits");
8503   ACCEPT (z, "bitswidth");
8504   ACCEPT (z, "byteswidth");
8505   ACCEPT (z, "smallreal");
8506   return (A68_FALSE);
8507 #undef ACCEPT
8508 }
8509 
8510 /**
8511 @brief Map "short sqrt" onto "sqrt" etcetera.
8512 @param u Name of routine.
8513 @return Tag to map onto.
8514 **/
8515 
8516 static TAG_T *
bind_lengthety_identifier(char * u)8517 bind_lengthety_identifier (char *u)
8518 {
8519 #define CAR(u, v) (strncmp (u, v, strlen(v)) == 0)
8520 /*
8521 We can only map routines blessed by "is_mappable_routine", so there is no
8522 "short print" or "long char in string".
8523 */
8524   if (CAR (u, "short")) {
8525     do {
8526       char *v;
8527       TAG_T *w;
8528       u = &u[strlen ("short")];
8529       v = TEXT (add_token (&top_token, u));
8530       w = find_tag_local (a68g_standenv, IDENTIFIER, v);
8531       if (w != NO_TAG && is_mappable_routine (v)) {
8532         return (w);
8533       }
8534     } while (CAR (u, "short"));
8535   } else if (CAR (u, "long")) {
8536     do {
8537       char *v;
8538       TAG_T *w;
8539       u = &u[strlen ("long")];
8540       v = TEXT (add_token (&top_token, u));
8541       w = find_tag_local (a68g_standenv, IDENTIFIER, v);
8542       if (w != NO_TAG && is_mappable_routine (v)) {
8543         return (w);
8544       }
8545     } while (CAR (u, "long"));
8546   }
8547   return (NO_TAG);
8548 #undef CAR
8549 }
8550 
8551 /**
8552 @brief Bind identifier tags to the symbol table.
8553 @param p Node in syntax tree.
8554 **/
8555 
8556 static void
bind_identifier_tag_to_symbol_table(NODE_T * p)8557 bind_identifier_tag_to_symbol_table (NODE_T * p)
8558 {
8559   for (; p != NO_NODE; FORWARD (p)) {
8560     bind_identifier_tag_to_symbol_table (SUB (p));
8561     if (is_one_of (p, IDENTIFIER, DEFINING_IDENTIFIER, STOP)) {
8562       int att = first_tag_global (TABLE (p), NSYMBOL (p));
8563       TAG_T *z;
8564       if (att == STOP) {
8565         if ((z = bind_lengthety_identifier (NSYMBOL (p))) != NO_TAG) {
8566           MOID (p) = MOID (z);
8567 /*
8568         } else {
8569           diagnostic_node (A68_ERROR, p, ERROR_UNDECLARED_TAG);
8570           z = add_tag (TABLE (p), IDENTIFIER, p, MODE (ERROR), NORMAL_IDENTIFIER);
8571           MOID (p) = MODE (ERROR);
8572 */
8573         }
8574         TAX (p) = z;
8575       } else {
8576         z = find_tag_global (TABLE (p), att, NSYMBOL (p));
8577         if (att == IDENTIFIER && z != NO_TAG) {
8578           MOID (p) = MOID (z);
8579         } else if (att == LABEL && z != NO_TAG) {
8580           ;
8581         } else if ((z = bind_lengthety_identifier (NSYMBOL (p))) != NO_TAG) {
8582           MOID (p) = MOID (z);
8583         } else {
8584           diagnostic_node (A68_ERROR, p, ERROR_UNDECLARED_TAG);
8585           z = add_tag (TABLE (p), IDENTIFIER, p, MODE (ERROR), NORMAL_IDENTIFIER);
8586           MOID (p) = MODE (ERROR);
8587         }
8588         TAX (p) = z;
8589         if (IS (p, DEFINING_IDENTIFIER)) {
8590           NODE (z) = p;
8591         }
8592       }
8593     }
8594   }
8595 }
8596 
8597 /**
8598 @brief Bind indicant tags to the symbol table.
8599 @param p Node in syntax tree.
8600 **/
8601 
8602 static void
bind_indicant_tag_to_symbol_table(NODE_T * p)8603 bind_indicant_tag_to_symbol_table (NODE_T * p)
8604 {
8605   for (; p != NO_NODE; FORWARD (p)) {
8606     bind_indicant_tag_to_symbol_table (SUB (p));
8607     if (is_one_of (p, INDICANT, DEFINING_INDICANT, STOP)) {
8608       TAG_T *z = find_tag_global (TABLE (p), INDICANT, NSYMBOL (p));
8609       if (z != NO_TAG) {
8610         MOID (p) = MOID (z);
8611         TAX (p) = z;
8612         if (IS (p, DEFINING_INDICANT)) {
8613           NODE (z) = p;
8614         }
8615       }
8616     }
8617   }
8618 }
8619 
8620 /**
8621 @brief Enter specifier identifiers in the symbol table.
8622 @param p Node in syntax tree.
8623 **/
8624 
8625 static void
tax_specifiers(NODE_T * p)8626 tax_specifiers (NODE_T * p)
8627 {
8628   for (; p != NO_NODE; FORWARD (p)) {
8629     tax_specifiers (SUB (p));
8630     if (SUB (p) != NO_NODE && IS (p, SPECIFIER)) {
8631       tax_specifier_list (SUB (p));
8632     }
8633   }
8634 }
8635 
8636 /**
8637 @brief Enter specifier identifiers in the symbol table.
8638 @param p Node in syntax tree.
8639 **/
8640 
8641 static void
tax_specifier_list(NODE_T * p)8642 tax_specifier_list (NODE_T * p)
8643 {
8644   if (p != NO_NODE) {
8645     if (IS (p, OPEN_SYMBOL)) {
8646       tax_specifier_list (NEXT (p));
8647     } else if (is_one_of (p, CLOSE_SYMBOL, VOID_SYMBOL, STOP)) {
8648       ;
8649     } else if (IS (p, IDENTIFIER)) {
8650       TAG_T *z = add_tag (TABLE (p), IDENTIFIER, p, NO_MOID, SPECIFIER_IDENTIFIER);
8651       HEAP (z) = LOC_SYMBOL;
8652     } else if (IS (p, DECLARER)) {
8653       tax_specifiers (SUB (p));
8654       tax_specifier_list (NEXT (p));
8655 /* last identifier entry is identifier with this declarer */
8656       if (IDENTIFIERS (TABLE (p)) != NO_TAG && PRIO (IDENTIFIERS (TABLE (p))) == SPECIFIER_IDENTIFIER)
8657         MOID (IDENTIFIERS (TABLE (p))) = MOID (p);
8658     }
8659   }
8660 }
8661 
8662 /**
8663 @brief Enter parameter identifiers in the symbol table.
8664 @param p Node in syntax tree.
8665 **/
8666 
8667 static void
tax_parameters(NODE_T * p)8668 tax_parameters (NODE_T * p)
8669 {
8670   for (; p != NO_NODE; FORWARD (p)) {
8671     if (SUB (p) != NO_NODE) {
8672       tax_parameters (SUB (p));
8673       if (IS (p, PARAMETER_PACK)) {
8674         tax_parameter_list (SUB (p));
8675       }
8676     }
8677   }
8678 }
8679 
8680 /**
8681 @brief Enter parameter identifiers in the symbol table.
8682 @param p Node in syntax tree.
8683 **/
8684 
8685 static void
tax_parameter_list(NODE_T * p)8686 tax_parameter_list (NODE_T * p)
8687 {
8688   if (p != NO_NODE) {
8689     if (is_one_of (p, OPEN_SYMBOL, COMMA_SYMBOL, STOP)) {
8690       tax_parameter_list (NEXT (p));
8691     } else if (IS (p, CLOSE_SYMBOL)) {
8692       ;
8693     } else if (is_one_of (p, PARAMETER_LIST, PARAMETER, STOP)) {
8694       tax_parameter_list (NEXT (p));
8695       tax_parameter_list (SUB (p));
8696     } else if (IS (p, IDENTIFIER)) {
8697 /* parameters are always local */
8698       HEAP (add_tag (TABLE (p), IDENTIFIER, p, NO_MOID, PARAMETER_IDENTIFIER)) = LOC_SYMBOL;
8699     } else if (IS (p, DECLARER)) {
8700       TAG_T *s;
8701       tax_parameter_list (NEXT (p));
8702 /* last identifier entries are identifiers with this declarer */
8703       for (s = IDENTIFIERS (TABLE (p)); s != NO_TAG && MOID (s) == NO_MOID; FORWARD (s)) {
8704         MOID (s) = MOID (p);
8705       }
8706       tax_parameters (SUB (p));
8707     }
8708   }
8709 }
8710 
8711 /**
8712 @brief Enter FOR identifiers in the symbol table.
8713 @param p Node in syntax tree.
8714 **/
8715 
8716 static void
tax_for_identifiers(NODE_T * p)8717 tax_for_identifiers (NODE_T * p)
8718 {
8719   for (; p != NO_NODE; FORWARD (p)) {
8720     tax_for_identifiers (SUB (p));
8721     if (IS (p, FOR_SYMBOL)) {
8722       if ((FORWARD (p)) != NO_NODE) {
8723         (void) add_tag (TABLE (p), IDENTIFIER, p, MODE (INT), LOOP_IDENTIFIER);
8724       }
8725     }
8726   }
8727 }
8728 
8729 /**
8730 @brief Enter routine texts in the symbol table.
8731 @param p Node in syntax tree.
8732 **/
8733 
8734 static void
tax_routine_texts(NODE_T * p)8735 tax_routine_texts (NODE_T * p)
8736 {
8737   for (; p != NO_NODE; FORWARD (p)) {
8738     tax_routine_texts (SUB (p));
8739     if (IS (p, ROUTINE_TEXT)) {
8740       TAG_T *z = add_tag (TABLE (p), ANONYMOUS, p, MOID (p), ROUTINE_TEXT);
8741       TAX (p) = z;
8742       HEAP (z) = LOC_SYMBOL;
8743       USE (z) = A68_TRUE;
8744     }
8745   }
8746 }
8747 
8748 /**
8749 @brief Enter format texts in the symbol table.
8750 @param p Node in syntax tree.
8751 **/
8752 
8753 static void
tax_format_texts(NODE_T * p)8754 tax_format_texts (NODE_T * p)
8755 {
8756   for (; p != NO_NODE; FORWARD (p)) {
8757     tax_format_texts (SUB (p));
8758     if (IS (p, FORMAT_TEXT)) {
8759       TAG_T *z = add_tag (TABLE (p), ANONYMOUS, p, MODE (FORMAT), FORMAT_TEXT);
8760       TAX (p) = z;
8761       USE (z) = A68_TRUE;
8762     } else if (IS (p, FORMAT_DELIMITER_SYMBOL) && NEXT (p) != NO_NODE) {
8763       TAG_T *z = add_tag (TABLE (p), ANONYMOUS, p, MODE (FORMAT), FORMAT_IDENTIFIER);
8764       TAX (p) = z;
8765       USE (z) = A68_TRUE;
8766     }
8767   }
8768 }
8769 
8770 /**
8771 @brief Enter FORMAT pictures in the symbol table.
8772 @param p Node in syntax tree.
8773 **/
8774 
8775 static void
tax_pictures(NODE_T * p)8776 tax_pictures (NODE_T * p)
8777 {
8778   for (; p != NO_NODE; FORWARD (p)) {
8779     tax_pictures (SUB (p));
8780     if (IS (p, PICTURE)) {
8781       TAX (p) = add_tag (TABLE (p), ANONYMOUS, p, MODE (COLLITEM), FORMAT_IDENTIFIER);
8782     }
8783   }
8784 }
8785 
8786 /**
8787 @brief Enter generators in the symbol table.
8788 @param p Node in syntax tree.
8789 **/
8790 
8791 static void
tax_generators(NODE_T * p)8792 tax_generators (NODE_T * p)
8793 {
8794   for (; p != NO_NODE; FORWARD (p)) {
8795     tax_generators (SUB (p));
8796     if (IS (p, GENERATOR)) {
8797       if (IS (SUB (p), LOC_SYMBOL)) {
8798         TAG_T *z = add_tag (TABLE (p), ANONYMOUS, p, SUB_MOID (SUB (p)), GENERATOR);
8799         HEAP (z) = LOC_SYMBOL;
8800         USE (z) = A68_TRUE;
8801         TAX (p) = z;
8802       }
8803     }
8804   }
8805 }
8806 
8807 /**
8808 @brief Find a firmly related operator for operands.
8809 @param c Symbol table.
8810 @param n Name of operator.
8811 @param l Left operand mode.
8812 @param r Right operand mode.
8813 @param self Own tag of "n", as to not relate to itself.
8814 @return Pointer to entry in table.
8815 **/
8816 
8817 static TAG_T *
find_firmly_related_op(TABLE_T * c,char * n,MOID_T * l,MOID_T * r,TAG_T * self)8818 find_firmly_related_op (TABLE_T * c, char *n, MOID_T * l, MOID_T * r, TAG_T * self)
8819 {
8820   if (c != NO_TABLE) {
8821     TAG_T *s = OPERATORS (c);
8822     for (; s != NO_TAG; FORWARD (s)) {
8823       if (s != self && NSYMBOL (NODE (s)) == n) {
8824         PACK_T *t = PACK (MOID (s));
8825         if (t != NO_PACK && is_firm (MOID (t), l)) {
8826 /* catch monadic operator */
8827           if ((FORWARD (t)) == NO_PACK) {
8828             if (r == NO_MOID) {
8829               return (s);
8830             }
8831           } else {
8832 /* catch dyadic operator */
8833             if (r != NO_MOID && is_firm (MOID (t), r)) {
8834               return (s);
8835             }
8836           }
8837         }
8838       }
8839     }
8840   }
8841   return (NO_TAG);
8842 }
8843 
8844 /**
8845 @brief Check for firmly related operators in this range.
8846 @param p Node in syntax tree.
8847 @param s Operator tag to start from.
8848 **/
8849 
8850 static void
test_firmly_related_ops_local(NODE_T * p,TAG_T * s)8851 test_firmly_related_ops_local (NODE_T * p, TAG_T * s)
8852 {
8853   if (s != NO_TAG) {
8854     PACK_T *u = PACK (MOID (s));
8855     if (u != NO_PACK) {
8856       MOID_T *l = MOID (u);
8857       MOID_T *r = (NEXT (u) != NO_PACK ? MOID (NEXT (u)) : NO_MOID);
8858       TAG_T *t = find_firmly_related_op (TAG_TABLE (s), NSYMBOL (NODE (s)), l, r, s);
8859       if (t != NO_TAG) {
8860         if (TAG_TABLE (t) == a68g_standenv) {
8861           diagnostic_node (A68_ERROR, p, ERROR_OPERATOR_RELATED, MOID (s), NSYMBOL (NODE (s)), MOID (t), NSYMBOL (NODE (t)));
8862           ABEND (A68_TRUE, "standard environ error", NO_TEXT);
8863         } else {
8864           diagnostic_node (A68_ERROR, p, ERROR_OPERATOR_RELATED, MOID (s), NSYMBOL (NODE (s)), MOID (t), NSYMBOL (NODE (t)));
8865         }
8866       }
8867     }
8868     if (NEXT (s) != NO_TAG) {
8869       test_firmly_related_ops_local ((p == NO_NODE ? NO_NODE : NODE (NEXT (s))), NEXT (s));
8870     }
8871   }
8872 }
8873 
8874 /**
8875 @brief Find firmly related operators in this program.
8876 @param p Node in syntax tree.
8877 **/
8878 
8879 static void
test_firmly_related_ops(NODE_T * p)8880 test_firmly_related_ops (NODE_T * p)
8881 {
8882   for (; p != NO_NODE; FORWARD (p)) {
8883     if (SUB (p) != NO_NODE && is_new_lexical_level (p)) {
8884       TAG_T *oops = OPERATORS (TABLE (SUB (p)));
8885       if (oops != NO_TAG) {
8886         test_firmly_related_ops_local (NODE (oops), oops);
8887       }
8888     }
8889     test_firmly_related_ops (SUB (p));
8890   }
8891 }
8892 
8893 /**
8894 @brief Driver for the processing of TAXes.
8895 @param p Node in syntax tree.
8896 **/
8897 
8898 void
collect_taxes(NODE_T * p)8899 collect_taxes (NODE_T * p)
8900 {
8901   tax_tags (p);
8902   tax_specifiers (p);
8903   tax_parameters (p);
8904   tax_for_identifiers (p);
8905   tax_routine_texts (p);
8906   tax_pictures (p);
8907   tax_format_texts (p);
8908   tax_generators (p);
8909   bind_identifier_tag_to_symbol_table (p);
8910   bind_indicant_tag_to_symbol_table (p);
8911   test_firmly_related_ops (p);
8912   test_firmly_related_ops_local (NO_NODE, OPERATORS (a68g_standenv));
8913 }
8914 
8915 /**
8916 @brief Whether tag has already been declared in this range.
8917 @param n Name of tag.
8918 @param a Attribute of tag.
8919 **/
8920 
8921 static void
already_declared(NODE_T * n,int a)8922 already_declared (NODE_T * n, int a)
8923 {
8924   if (find_tag_local (TABLE (n), a, NSYMBOL (n)) != NO_TAG) {
8925     diagnostic_node (A68_ERROR, n, ERROR_MULTIPLE_TAG);
8926   }
8927 }
8928 
8929 /**
8930 @brief Whether tag has already been declared in this range.
8931 @param n Name of tag.
8932 @param a Attribute of tag.
8933 **/
8934 
8935 static void
already_declared_hidden(NODE_T * n,int a)8936 already_declared_hidden (NODE_T * n, int a)
8937 {
8938   TAG_T *s;
8939   if (find_tag_local (TABLE (n), a, NSYMBOL (n)) != NO_TAG) {
8940     diagnostic_node (A68_ERROR, n, ERROR_MULTIPLE_TAG);
8941   }
8942   if ((s = find_tag_global (PREVIOUS (TABLE (n)), a, NSYMBOL (n))) != NO_TAG) {
8943     if (TAG_TABLE (s) == a68g_standenv) {
8944       diagnostic_node (A68_WARNING, n, WARNING_HIDES_PRELUDE, MOID (s), NSYMBOL (n));
8945     } else {
8946       diagnostic_node (A68_WARNING, n, WARNING_HIDES, NSYMBOL (n));
8947     }
8948   }
8949 }
8950 
8951 /**
8952 @brief Add tag to local symbol table.
8953 @param s Table where to insert.
8954 @param a Attribute.
8955 @param n Name of tag.
8956 @param m Mode of tag.
8957 @param p Node in syntax tree.
8958 @return Entry in symbol table.
8959 **/
8960 
8961 TAG_T *
add_tag(TABLE_T * s,int a,NODE_T * n,MOID_T * m,int p)8962 add_tag (TABLE_T * s, int a, NODE_T * n, MOID_T * m, int p)
8963 {
8964 #define INSERT_TAG(l, n) {NEXT (n) = *(l); *(l) = (n);}
8965   if (s != NO_TABLE) {
8966     TAG_T *z = new_tag ();
8967     TAG_TABLE (z) = s;
8968     PRIO (z) = p;
8969     MOID (z) = m;
8970     NODE (z) = n;
8971 /*    TAX(n) = z; */
8972     switch (a) {
8973     case IDENTIFIER:{
8974         already_declared_hidden (n, IDENTIFIER);
8975         already_declared_hidden (n, LABEL);
8976         INSERT_TAG (&IDENTIFIERS (s), z);
8977         break;
8978       }
8979     case INDICANT:{
8980         already_declared_hidden (n, INDICANT);
8981         already_declared (n, OP_SYMBOL);
8982         already_declared (n, PRIO_SYMBOL);
8983         INSERT_TAG (&INDICANTS (s), z);
8984         break;
8985       }
8986     case LABEL:{
8987         already_declared_hidden (n, LABEL);
8988         already_declared_hidden (n, IDENTIFIER);
8989         INSERT_TAG (&LABELS (s), z);
8990         break;
8991       }
8992     case OP_SYMBOL:{
8993         already_declared (n, INDICANT);
8994         INSERT_TAG (&OPERATORS (s), z);
8995         break;
8996       }
8997     case PRIO_SYMBOL:{
8998         already_declared (n, PRIO_SYMBOL);
8999         already_declared (n, INDICANT);
9000         INSERT_TAG (&PRIO (s), z);
9001         break;
9002       }
9003     case ANONYMOUS:{
9004         INSERT_TAG (&ANONYMOUS (s), z);
9005         break;
9006       }
9007     default:{
9008         ABEND (A68_TRUE, ERROR_INTERNAL_CONSISTENCY, "add tag");
9009       }
9010     }
9011     return (z);
9012   } else {
9013     return (NO_TAG);
9014   }
9015 }
9016 
9017 /**
9018 @brief Find a tag, searching symbol tables towards the root.
9019 @param table Symbol table to search.
9020 @param a Attribute of tag.
9021 @param name Name of tag.
9022 @return Entry in symbol table.
9023 **/
9024 
9025 TAG_T *
find_tag_global(TABLE_T * table,int a,char * name)9026 find_tag_global (TABLE_T * table, int a, char *name)
9027 {
9028   if (table != NO_TABLE) {
9029     TAG_T *s = NO_TAG;
9030     switch (a) {
9031     case IDENTIFIER:{
9032         s = IDENTIFIERS (table);
9033         break;
9034       }
9035     case INDICANT:{
9036         s = INDICANTS (table);
9037         break;
9038       }
9039     case LABEL:{
9040         s = LABELS (table);
9041         break;
9042       }
9043     case OP_SYMBOL:{
9044         s = OPERATORS (table);
9045         break;
9046       }
9047     case PRIO_SYMBOL:{
9048         s = PRIO (table);
9049         break;
9050       }
9051     default:{
9052         ABEND (A68_TRUE, "impossible state in find_tag_global", NO_TEXT);
9053         break;
9054       }
9055     }
9056     for (; s != NO_TAG; FORWARD (s)) {
9057       if (NSYMBOL (NODE (s)) == name) {
9058         return (s);
9059       }
9060     }
9061     return (find_tag_global (PREVIOUS (table), a, name));
9062   } else {
9063     return (NO_TAG);
9064   }
9065 }
9066 
9067 /**
9068 @brief Whether identifier or label global.
9069 @param table Symbol table to search.
9070 @param name Name of tag.
9071 @return Attribute of tag.
9072 **/
9073 
9074 int
is_identifier_or_label_global(TABLE_T * table,char * name)9075 is_identifier_or_label_global (TABLE_T * table, char *name)
9076 {
9077   if (table != NO_TABLE) {
9078     TAG_T *s;
9079     for (s = IDENTIFIERS (table); s != NO_TAG; FORWARD (s)) {
9080       if (NSYMBOL (NODE (s)) == name) {
9081         return (IDENTIFIER);
9082       }
9083     }
9084     for (s = LABELS (table); s != NO_TAG; FORWARD (s)) {
9085       if (NSYMBOL (NODE (s)) == name) {
9086         return (LABEL);
9087       }
9088     }
9089     return (is_identifier_or_label_global (PREVIOUS (table), name));
9090   } else {
9091     return (0);
9092   }
9093 }
9094 
9095 /**
9096 @brief Find a tag, searching only local symbol table.
9097 @param table Symbol table to search.
9098 @param a Attribute of tag.
9099 @param name Name of tag.
9100 @return Entry in symbol table.
9101 **/
9102 
9103 TAG_T *
find_tag_local(TABLE_T * table,int a,char * name)9104 find_tag_local (TABLE_T * table, int a, char *name)
9105 {
9106   if (table != NO_TABLE) {
9107     TAG_T *s = NO_TAG;
9108     if (a == OP_SYMBOL) {
9109       s = OPERATORS (table);
9110     } else if (a == PRIO_SYMBOL) {
9111       s = PRIO (table);
9112     } else if (a == IDENTIFIER) {
9113       s = IDENTIFIERS (table);
9114     } else if (a == INDICANT) {
9115       s = INDICANTS (table);
9116     } else if (a == LABEL) {
9117       s = LABELS (table);
9118     } else {
9119       ABEND (A68_TRUE, "impossible state in find_tag_local", NO_TEXT);
9120     }
9121     for (; s != NO_TAG; FORWARD (s)) {
9122       if (NSYMBOL (NODE (s)) == name) {
9123         return (s);
9124       }
9125     }
9126   }
9127   return (NO_TAG);
9128 }
9129 
9130 /**
9131 @brief Whether context specifies HEAP or LOC for an identifier.
9132 @param p Node in syntax tree.
9133 @return Attribute of generator.
9134 **/
9135 
9136 static int
tab_qualifier(NODE_T * p)9137 tab_qualifier (NODE_T * p)
9138 {
9139   if (p != NO_NODE) {
9140     if (is_one_of (p, UNIT, ASSIGNATION, TERTIARY, SECONDARY, GENERATOR, STOP)) {
9141       return (tab_qualifier (SUB (p)));
9142     } else if (is_one_of (p, LOC_SYMBOL, HEAP_SYMBOL, NEW_SYMBOL, STOP)) {
9143       return (ATTRIBUTE (p) == LOC_SYMBOL ? LOC_SYMBOL : HEAP_SYMBOL);
9144     } else {
9145       return (LOC_SYMBOL);
9146     }
9147   } else {
9148     return (LOC_SYMBOL);
9149   }
9150 }
9151 
9152 /**
9153 @brief Enter identity declarations in the symbol table.
9154 @param p Node in syntax tree.
9155 @param m Mode of identifiers to enter (picked from the left-most one in fi. INT i = 1, j = 2).
9156 **/
9157 
9158 static void
tax_identity_dec(NODE_T * p,MOID_T ** m)9159 tax_identity_dec (NODE_T * p, MOID_T ** m)
9160 {
9161   if (p != NO_NODE) {
9162     if (IS (p, IDENTITY_DECLARATION)) {
9163       tax_identity_dec (SUB (p), m);
9164       tax_identity_dec (NEXT (p), m);
9165     } else if (IS (p, DECLARER)) {
9166       tax_tags (SUB (p));
9167       *m = MOID (p);
9168       tax_identity_dec (NEXT (p), m);
9169     } else if (IS (p, COMMA_SYMBOL)) {
9170       tax_identity_dec (NEXT (p), m);
9171     } else if (IS (p, DEFINING_IDENTIFIER)) {
9172       TAG_T *entry = find_tag_local (TABLE (p), IDENTIFIER, NSYMBOL (p));
9173       MOID (p) = *m;
9174       HEAP (entry) = LOC_SYMBOL;
9175       TAX (p) = entry;
9176       MOID (entry) = *m;
9177       if (ATTRIBUTE (*m) == REF_SYMBOL) {
9178         HEAP (entry) = tab_qualifier (NEXT_NEXT (p));
9179       }
9180       tax_identity_dec (NEXT_NEXT (p), m);
9181     } else {
9182       tax_tags (p);
9183     }
9184   }
9185 }
9186 
9187 /**
9188 @brief Enter variable declarations in the symbol table.
9189 @param p Node in syntax tree.
9190 @param q Qualifier of generator (HEAP, LOC) picked from left-most identifier.
9191 @param m Mode of identifiers to enter (picked from the left-most one in fi. INT i, j, k).
9192 **/
9193 
9194 static void
tax_variable_dec(NODE_T * p,int * q,MOID_T ** m)9195 tax_variable_dec (NODE_T * p, int *q, MOID_T ** m)
9196 {
9197   if (p != NO_NODE) {
9198     if (IS (p, VARIABLE_DECLARATION)) {
9199       tax_variable_dec (SUB (p), q, m);
9200       tax_variable_dec (NEXT (p), q, m);
9201     } else if (IS (p, DECLARER)) {
9202       tax_tags (SUB (p));
9203       *m = MOID (p);
9204       tax_variable_dec (NEXT (p), q, m);
9205     } else if (IS (p, QUALIFIER)) {
9206       *q = ATTRIBUTE (SUB (p));
9207       tax_variable_dec (NEXT (p), q, m);
9208     } else if (IS (p, COMMA_SYMBOL)) {
9209       tax_variable_dec (NEXT (p), q, m);
9210     } else if (IS (p, DEFINING_IDENTIFIER)) {
9211       TAG_T *entry = find_tag_local (TABLE (p), IDENTIFIER, NSYMBOL (p));
9212       MOID (p) = *m;
9213       TAX (p) = entry;
9214       HEAP (entry) = *q;
9215       if (*q == LOC_SYMBOL) {
9216         TAG_T *z = add_tag (TABLE (p), ANONYMOUS, p, SUB (*m), GENERATOR);
9217         HEAP (z) = LOC_SYMBOL;
9218         USE (z) = A68_TRUE;
9219         BODY (entry) = z;
9220       } else {
9221         BODY (entry) = NO_TAG;
9222       }
9223       MOID (entry) = *m;
9224       tax_variable_dec (NEXT (p), q, m);
9225     } else {
9226       tax_tags (p);
9227     }
9228   }
9229 }
9230 
9231 /**
9232 @brief Enter procedure variable declarations in the symbol table.
9233 @param p Node in syntax tree.
9234 @param q Qualifier of generator (HEAP, LOC) picked from left-most identifier.
9235 **/
9236 
9237 static void
tax_proc_variable_dec(NODE_T * p,int * q)9238 tax_proc_variable_dec (NODE_T * p, int *q)
9239 {
9240   if (p != NO_NODE) {
9241     if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
9242       tax_proc_variable_dec (SUB (p), q);
9243       tax_proc_variable_dec (NEXT (p), q);
9244     } else if (IS (p, QUALIFIER)) {
9245       *q = ATTRIBUTE (SUB (p));
9246       tax_proc_variable_dec (NEXT (p), q);
9247     } else if (is_one_of (p, PROC_SYMBOL, COMMA_SYMBOL, STOP)) {
9248       tax_proc_variable_dec (NEXT (p), q);
9249     } else if (IS (p, DEFINING_IDENTIFIER)) {
9250       TAG_T *entry = find_tag_local (TABLE (p), IDENTIFIER, NSYMBOL (p));
9251       TAX (p) = entry;
9252       HEAP (entry) = *q;
9253       MOID (entry) = MOID (p);
9254       if (*q == LOC_SYMBOL) {
9255         TAG_T *z = add_tag (TABLE (p), ANONYMOUS, p, SUB_MOID (p), GENERATOR);
9256         HEAP (z) = LOC_SYMBOL;
9257         USE (z) = A68_TRUE;
9258         BODY (entry) = z;
9259       } else {
9260         BODY (entry) = NO_TAG;
9261       }
9262       tax_proc_variable_dec (NEXT (p), q);
9263     } else {
9264       tax_tags (p);
9265     }
9266   }
9267 }
9268 
9269 /**
9270 @brief Enter procedure declarations in the symbol table.
9271 @param p Node in syntax tree.
9272 **/
9273 
9274 static void
tax_proc_dec(NODE_T * p)9275 tax_proc_dec (NODE_T * p)
9276 {
9277   if (p != NO_NODE) {
9278     if (IS (p, PROCEDURE_DECLARATION)) {
9279       tax_proc_dec (SUB (p));
9280       tax_proc_dec (NEXT (p));
9281     } else if (is_one_of (p, PROC_SYMBOL, COMMA_SYMBOL, STOP)) {
9282       tax_proc_dec (NEXT (p));
9283     } else if (IS (p, DEFINING_IDENTIFIER)) {
9284       TAG_T *entry = find_tag_local (TABLE (p), IDENTIFIER, NSYMBOL (p));
9285       MOID_T *m = MOID (NEXT_NEXT (p));
9286       MOID (p) = m;
9287       TAX (p) = entry;
9288       CODEX (entry) |= PROC_DECLARATION_MASK;
9289       HEAP (entry) = LOC_SYMBOL;
9290       MOID (entry) = m;
9291       tax_proc_dec (NEXT (p));
9292     } else {
9293       tax_tags (p);
9294     }
9295   }
9296 }
9297 
9298 /**
9299 @brief Check validity of operator declaration.
9300 @param p Node in syntax tree.
9301 @param u Moid for a operator-plan.
9302 **/
9303 
9304 static void
check_operator_dec(NODE_T * p,MOID_T * u)9305 check_operator_dec (NODE_T * p, MOID_T * u)
9306 {
9307   int k = 0;
9308   if (u == NO_MOID) {
9309     NODE_T *pack = SUB_SUB (NEXT_NEXT (p));     /* Where the parameter pack is */
9310     if (ATTRIBUTE (NEXT_NEXT (p)) != ROUTINE_TEXT) {
9311       pack = SUB (pack);
9312     }
9313     k = 1 + count_operands (pack);
9314   } else {
9315     k = count_pack_members (PACK (u));
9316   }
9317   if (k < 1 && k > 2) {
9318     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_OPERAND_NUMBER);
9319     k = 0;
9320   }
9321   if (k == 1 && a68g_strchr (NOMADS, NSYMBOL (p)[0]) != NO_TEXT) {
9322     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_OPERATOR_INVALID, NOMADS);
9323   } else if (k == 2 && !find_tag_global (TABLE (p), PRIO_SYMBOL, NSYMBOL (p))) {
9324     diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_DYADIC_PRIORITY);
9325   }
9326 }
9327 
9328 /**
9329 @brief Enter operator declarations in the symbol table.
9330 @param p Node in syntax tree.
9331 @param m Mode of operators to enter (picked from the left-most one).
9332 **/
9333 
9334 static void
tax_op_dec(NODE_T * p,MOID_T ** m)9335 tax_op_dec (NODE_T * p, MOID_T ** m)
9336 {
9337   if (p != NO_NODE) {
9338     if (IS (p, OPERATOR_DECLARATION)) {
9339       tax_op_dec (SUB (p), m);
9340       tax_op_dec (NEXT (p), m);
9341     } else if (IS (p, OPERATOR_PLAN)) {
9342       tax_tags (SUB (p));
9343       *m = MOID (p);
9344       tax_op_dec (NEXT (p), m);
9345     } else if (IS (p, OP_SYMBOL)) {
9346       tax_op_dec (NEXT (p), m);
9347     } else if (IS (p, COMMA_SYMBOL)) {
9348       tax_op_dec (NEXT (p), m);
9349     } else if (IS (p, DEFINING_OPERATOR)) {
9350       TAG_T *entry = OPERATORS (TABLE (p));
9351       check_operator_dec (p, *m);
9352       while (entry != NO_TAG && NODE (entry) != p) {
9353         FORWARD (entry);
9354       }
9355       MOID (p) = *m;
9356       TAX (p) = entry;
9357       HEAP (entry) = LOC_SYMBOL;
9358       MOID (entry) = *m;
9359       tax_op_dec (NEXT (p), m);
9360     } else {
9361       tax_tags (p);
9362     }
9363   }
9364 }
9365 
9366 /**
9367 @brief Enter brief operator declarations in the symbol table.
9368 @param p Node in syntax tree.
9369 **/
9370 
9371 static void
tax_brief_op_dec(NODE_T * p)9372 tax_brief_op_dec (NODE_T * p)
9373 {
9374   if (p != NO_NODE) {
9375     if (IS (p, BRIEF_OPERATOR_DECLARATION)) {
9376       tax_brief_op_dec (SUB (p));
9377       tax_brief_op_dec (NEXT (p));
9378     } else if (is_one_of (p, OP_SYMBOL, COMMA_SYMBOL, STOP)) {
9379       tax_brief_op_dec (NEXT (p));
9380     } else if (IS (p, DEFINING_OPERATOR)) {
9381       TAG_T *entry = OPERATORS (TABLE (p));
9382       MOID_T *m = MOID (NEXT_NEXT (p));
9383       check_operator_dec (p, NO_MOID);
9384       while (entry != NO_TAG && NODE (entry) != p) {
9385         FORWARD (entry);
9386       }
9387       MOID (p) = m;
9388       TAX (p) = entry;
9389       HEAP (entry) = LOC_SYMBOL;
9390       MOID (entry) = m;
9391       tax_brief_op_dec (NEXT (p));
9392     } else {
9393       tax_tags (p);
9394     }
9395   }
9396 }
9397 
9398 /**
9399 @brief Enter priority declarations in the symbol table.
9400 @param p Node in syntax tree.
9401 **/
9402 
9403 static void
tax_prio_dec(NODE_T * p)9404 tax_prio_dec (NODE_T * p)
9405 {
9406   if (p != NO_NODE) {
9407     if (IS (p, PRIORITY_DECLARATION)) {
9408       tax_prio_dec (SUB (p));
9409       tax_prio_dec (NEXT (p));
9410     } else if (is_one_of (p, PRIO_SYMBOL, COMMA_SYMBOL, STOP)) {
9411       tax_prio_dec (NEXT (p));
9412     } else if (IS (p, DEFINING_OPERATOR)) {
9413       TAG_T *entry = PRIO (TABLE (p));
9414       while (entry != NO_TAG && NODE (entry) != p) {
9415         FORWARD (entry);
9416       }
9417       MOID (p) = NO_MOID;
9418       TAX (p) = entry;
9419       HEAP (entry) = LOC_SYMBOL;
9420       tax_prio_dec (NEXT (p));
9421     } else {
9422       tax_tags (p);
9423     }
9424   }
9425 }
9426 
9427 /**
9428 @brief Enter TAXes in the symbol table.
9429 @param p Node in syntax tree.
9430 **/
9431 
9432 static void
tax_tags(NODE_T * p)9433 tax_tags (NODE_T * p)
9434 {
9435   for (; p != NO_NODE; FORWARD (p)) {
9436     int heap = LOC_SYMBOL;
9437     MOID_T *m = NO_MOID;
9438     if (IS (p, IDENTITY_DECLARATION)) {
9439       tax_identity_dec (p, &m);
9440     } else if (IS (p, VARIABLE_DECLARATION)) {
9441       tax_variable_dec (p, &heap, &m);
9442     } else if (IS (p, PROCEDURE_DECLARATION)) {
9443       tax_proc_dec (p);
9444     } else if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
9445       tax_proc_variable_dec (p, &heap);
9446     } else if (IS (p, OPERATOR_DECLARATION)) {
9447       tax_op_dec (p, &m);
9448     } else if (IS (p, BRIEF_OPERATOR_DECLARATION)) {
9449       tax_brief_op_dec (p);
9450     } else if (IS (p, PRIORITY_DECLARATION)) {
9451       tax_prio_dec (p);
9452     } else {
9453       tax_tags (SUB (p));
9454     }
9455   }
9456 }
9457 
9458 /**
9459 @brief Reset symbol table nest count.
9460 @param p Node in syntax tree.
9461 **/
9462 
9463 void
reset_symbol_table_nest_count(NODE_T * p)9464 reset_symbol_table_nest_count (NODE_T * p)
9465 {
9466   for (; p != NO_NODE; FORWARD (p)) {
9467     if (SUB (p) != NO_NODE && is_new_lexical_level (p)) {
9468       NEST (TABLE (SUB (p))) = symbol_table_count++;
9469     }
9470     reset_symbol_table_nest_count (SUB (p));
9471   }
9472 }
9473 
9474 /**
9475 @brief Bind routines in symbol table to the tree.
9476 @param p Node in syntax tree.
9477 **/
9478 
9479 void
bind_routine_tags_to_tree(NODE_T * p)9480 bind_routine_tags_to_tree (NODE_T * p)
9481 {
9482 /* By inserting coercions etc. some may have shifted */
9483   for (; p != NO_NODE; FORWARD (p)) {
9484     if (IS (p, ROUTINE_TEXT) && TAX (p) != NO_TAG) {
9485       NODE (TAX (p)) = p;
9486     }
9487     bind_routine_tags_to_tree (SUB (p));
9488   }
9489 }
9490 
9491 /**
9492 @brief Bind formats in symbol table to tree.
9493 @param p Node in syntax tree.
9494 **/
9495 
9496 void
bind_format_tags_to_tree(NODE_T * p)9497 bind_format_tags_to_tree (NODE_T * p)
9498 {
9499 /* By inserting coercions etc. some may have shifted */
9500   for (; p != NO_NODE; FORWARD (p)) {
9501     if (IS (p, FORMAT_TEXT) && TAX (p) != NO_TAG) {
9502       NODE (TAX (p)) = p;
9503     } else if (IS (p, FORMAT_DELIMITER_SYMBOL) && NEXT (p) != NO_NODE && TAX (p) != NO_TAG) {
9504       NODE (TAX (p)) = p;
9505     }
9506     bind_format_tags_to_tree (SUB (p));
9507   }
9508 }
9509 
9510 /**
9511 @brief Fill outer level of symbol table.
9512 @param p Node in syntax tree.
9513 @param s Parent symbol table.
9514 **/
9515 
9516 void
fill_symbol_table_outer(NODE_T * p,TABLE_T * s)9517 fill_symbol_table_outer (NODE_T * p, TABLE_T * s)
9518 {
9519   for (; p != NO_NODE; FORWARD (p)) {
9520     if (TABLE (p) != NO_TABLE) {
9521       OUTER (TABLE (p)) = s;
9522     }
9523     if (SUB (p) != NO_NODE && IS (p, ROUTINE_TEXT)) {
9524       fill_symbol_table_outer (SUB (p), TABLE (SUB (p)));
9525     } else if (SUB (p) != NO_NODE && IS (p, FORMAT_TEXT)) {
9526       fill_symbol_table_outer (SUB (p), TABLE (SUB (p)));
9527     } else {
9528       fill_symbol_table_outer (SUB (p), s);
9529     }
9530   }
9531 }
9532 
9533 /**
9534 @brief Flood branch in tree with local symbol table "s".
9535 @param p Node in syntax tree.
9536 @param s Parent symbol table.
9537 **/
9538 
9539 static void
flood_with_symbol_table_restricted(NODE_T * p,TABLE_T * s)9540 flood_with_symbol_table_restricted (NODE_T * p, TABLE_T * s)
9541 {
9542   for (; p != NO_NODE; FORWARD (p)) {
9543     TABLE (p) = s;
9544     if (ATTRIBUTE (p) != ROUTINE_TEXT && ATTRIBUTE (p) != SPECIFIED_UNIT) {
9545       if (is_new_lexical_level (p)) {
9546         PREVIOUS (TABLE (SUB (p))) = s;
9547       } else {
9548         flood_with_symbol_table_restricted (SUB (p), s);
9549       }
9550     }
9551   }
9552 }
9553 
9554 /**
9555 @brief Final structure of symbol table after parsing.
9556 @param p Node in syntax tree.
9557 @param l Current lexical level.
9558 **/
9559 
9560 void
finalise_symbol_table_setup(NODE_T * p,int l)9561 finalise_symbol_table_setup (NODE_T * p, int l)
9562 {
9563   TABLE_T *s = TABLE (p);
9564   NODE_T *q = p;
9565   while (q != NO_NODE) {
9566 /* routine texts are ranges */
9567     if (IS (q, ROUTINE_TEXT)) {
9568       flood_with_symbol_table_restricted (SUB (q), new_symbol_table (s));
9569     }
9570 /* specifiers are ranges */
9571     else if (IS (q, SPECIFIED_UNIT)) {
9572       flood_with_symbol_table_restricted (SUB (q), new_symbol_table (s));
9573     }
9574 /* level count and recursion */
9575     if (SUB (q) != NO_NODE) {
9576       if (is_new_lexical_level (q)) {
9577         LEX_LEVEL (SUB (q)) = l + 1;
9578         PREVIOUS (TABLE (SUB (q))) = s;
9579         finalise_symbol_table_setup (SUB (q), l + 1);
9580         if (IS (q, WHILE_PART)) {
9581 /* This was a bug that went unnoticed for 15 years! */
9582           TABLE_T *s2 = TABLE (SUB (q));
9583           if ((FORWARD (q)) == NO_NODE) {
9584             return;
9585           }
9586           if (IS (q, ALT_DO_PART)) {
9587             PREVIOUS (TABLE (SUB (q))) = s2;
9588             LEX_LEVEL (SUB (q)) = l + 2;
9589             finalise_symbol_table_setup (SUB (q), l + 2);
9590           }
9591         }
9592       } else {
9593         TABLE (SUB (q)) = s;
9594         finalise_symbol_table_setup (SUB (q), l);
9595       }
9596     }
9597     TABLE (q) = s;
9598     if (IS (q, FOR_SYMBOL)) {
9599       FORWARD (q);
9600     }
9601     FORWARD (q);
9602   }
9603 /* FOR identifiers are in the DO ... OD range */
9604   for (q = p; q != NO_NODE; FORWARD (q)) {
9605     if (IS (q, FOR_SYMBOL)) {
9606       TABLE (NEXT (q)) = TABLE (SEQUENCE (NEXT (q)));
9607     }
9608   }
9609 }
9610 
9611 /**
9612 @brief First structure of symbol table for parsing.
9613 @param p Node in syntax tree.
9614 **/
9615 
9616 void
preliminary_symbol_table_setup(NODE_T * p)9617 preliminary_symbol_table_setup (NODE_T * p)
9618 {
9619   NODE_T *q;
9620   TABLE_T *s = TABLE (p);
9621   BOOL_T not_a_for_range = A68_FALSE;
9622 /* let the tree point to the current symbol table */
9623   for (q = p; q != NO_NODE; FORWARD (q)) {
9624     TABLE (q) = s;
9625   }
9626 /* insert new tables when required */
9627   for (q = p; q != NO_NODE && !not_a_for_range; FORWARD (q)) {
9628     if (SUB (q) != NO_NODE) {
9629 /* BEGIN ... END, CODE ... EDOC, DEF ... FED, DO ... OD, $ ... $, { ... } are ranges */
9630       if (is_one_of (q, BEGIN_SYMBOL, DO_SYMBOL, ALT_DO_SYMBOL, FORMAT_DELIMITER_SYMBOL, ACCO_SYMBOL, STOP)) {
9631         TABLE (SUB (q)) = new_symbol_table (s);
9632         preliminary_symbol_table_setup (SUB (q));
9633       }
9634 /* ( ... ) is a range */
9635       else if (IS (q, OPEN_SYMBOL)) {
9636         if (whether (q, OPEN_SYMBOL, THEN_BAR_SYMBOL, STOP)) {
9637           TABLE (SUB (q)) = s;
9638           preliminary_symbol_table_setup (SUB (q));
9639           FORWARD (q);
9640           TABLE (SUB (q)) = new_symbol_table (s);
9641           preliminary_symbol_table_setup (SUB (q));
9642           if ((FORWARD (q)) == NO_NODE) {
9643             not_a_for_range = A68_TRUE;
9644           } else {
9645             if (IS (q, THEN_BAR_SYMBOL)) {
9646               TABLE (SUB (q)) = new_symbol_table (s);
9647               preliminary_symbol_table_setup (SUB (q));
9648             }
9649             if (IS (q, OPEN_SYMBOL)) {
9650               TABLE (SUB (q)) = new_symbol_table (s);
9651               preliminary_symbol_table_setup (SUB (q));
9652             }
9653           }
9654         } else {
9655 /* don't worry about STRUCT (...), UNION (...), PROC (...) yet */
9656           TABLE (SUB (q)) = new_symbol_table (s);
9657           preliminary_symbol_table_setup (SUB (q));
9658         }
9659       }
9660 /* IF ... THEN ... ELSE ... FI are ranges */
9661       else if (IS (q, IF_SYMBOL)) {
9662         if (whether (q, IF_SYMBOL, THEN_SYMBOL, STOP)) {
9663           TABLE (SUB (q)) = s;
9664           preliminary_symbol_table_setup (SUB (q));
9665           FORWARD (q);
9666           TABLE (SUB (q)) = new_symbol_table (s);
9667           preliminary_symbol_table_setup (SUB (q));
9668           if ((FORWARD (q)) == NO_NODE) {
9669             not_a_for_range = A68_TRUE;
9670           } else {
9671             if (IS (q, ELSE_SYMBOL)) {
9672               TABLE (SUB (q)) = new_symbol_table (s);
9673               preliminary_symbol_table_setup (SUB (q));
9674             }
9675             if (IS (q, IF_SYMBOL)) {
9676               TABLE (SUB (q)) = new_symbol_table (s);
9677               preliminary_symbol_table_setup (SUB (q));
9678             }
9679           }
9680         } else {
9681           TABLE (SUB (q)) = new_symbol_table (s);
9682           preliminary_symbol_table_setup (SUB (q));
9683         }
9684       }
9685 /* CASE ... IN ... OUT ... ESAC are ranges */
9686       else if (IS (q, CASE_SYMBOL)) {
9687         if (whether (q, CASE_SYMBOL, IN_SYMBOL, STOP)) {
9688           TABLE (SUB (q)) = s;
9689           preliminary_symbol_table_setup (SUB (q));
9690           FORWARD (q);
9691           TABLE (SUB (q)) = new_symbol_table (s);
9692           preliminary_symbol_table_setup (SUB (q));
9693           if ((FORWARD (q)) == NO_NODE) {
9694             not_a_for_range = A68_TRUE;
9695           } else {
9696             if (IS (q, OUT_SYMBOL)) {
9697               TABLE (SUB (q)) = new_symbol_table (s);
9698               preliminary_symbol_table_setup (SUB (q));
9699             }
9700             if (IS (q, CASE_SYMBOL)) {
9701               TABLE (SUB (q)) = new_symbol_table (s);
9702               preliminary_symbol_table_setup (SUB (q));
9703             }
9704           }
9705         } else {
9706           TABLE (SUB (q)) = new_symbol_table (s);
9707           preliminary_symbol_table_setup (SUB (q));
9708         }
9709       }
9710 /* UNTIL ... OD is a range */
9711       else if (IS (q, UNTIL_SYMBOL) && SUB (q) != NO_NODE) {
9712         TABLE (SUB (q)) = new_symbol_table (s);
9713         preliminary_symbol_table_setup (SUB (q));
9714 /* WHILE ... DO ... OD are ranges */
9715       } else if (IS (q, WHILE_SYMBOL)) {
9716         TABLE_T *u = new_symbol_table (s);
9717         TABLE (SUB (q)) = u;
9718         preliminary_symbol_table_setup (SUB (q));
9719         if ((FORWARD (q)) == NO_NODE) {
9720           not_a_for_range = A68_TRUE;
9721         } else if (IS (q, ALT_DO_SYMBOL)) {
9722           TABLE (SUB (q)) = new_symbol_table (u);
9723           preliminary_symbol_table_setup (SUB (q));
9724         }
9725       } else {
9726         TABLE (SUB (q)) = s;
9727         preliminary_symbol_table_setup (SUB (q));
9728       }
9729     }
9730   }
9731 /* FOR identifiers will go to the DO ... OD range */
9732   if (!not_a_for_range) {
9733     for (q = p; q != NO_NODE; FORWARD (q)) {
9734       if (IS (q, FOR_SYMBOL)) {
9735         NODE_T *r = q;
9736         TABLE (NEXT (q)) = NO_TABLE;
9737         for (; r != NO_NODE && TABLE (NEXT (q)) == NO_TABLE; FORWARD (r)) {
9738           if ((is_one_of (r, WHILE_SYMBOL, ALT_DO_SYMBOL, STOP)) && (NEXT (q) != NO_NODE && SUB (r) != NO_NODE)) {
9739             TABLE (NEXT (q)) = TABLE (SUB (r));
9740             SEQUENCE (NEXT (q)) = SUB (r);
9741           }
9742         }
9743       }
9744     }
9745   }
9746 }
9747 
9748 /**
9749 @brief Mark a mode as in use.
9750 @param m Mode to mark.
9751 **/
9752 
9753 static void
mark_mode(MOID_T * m)9754 mark_mode (MOID_T * m)
9755 {
9756   if (m != NO_MOID && USE (m) == A68_FALSE) {
9757     PACK_T *p = PACK (m);
9758     USE (m) = A68_TRUE;
9759     for (; p != NO_PACK; FORWARD (p)) {
9760       mark_mode (MOID (p));
9761       mark_mode (SUB (m));
9762       mark_mode (SLICE (m));
9763     }
9764   }
9765 }
9766 
9767 /**
9768 @brief Traverse tree and mark modes as used.
9769 @param p Node in syntax tree.
9770 **/
9771 
9772 void
mark_moids(NODE_T * p)9773 mark_moids (NODE_T * p)
9774 {
9775   for (; p != NO_NODE; FORWARD (p)) {
9776     mark_moids (SUB (p));
9777     if (MOID (p) != NO_MOID) {
9778       mark_mode (MOID (p));
9779     }
9780   }
9781 }
9782 
9783 /**
9784 @brief Mark various tags as used.
9785 @param p Node in syntax tree.
9786 **/
9787 
9788 void
mark_auxilliary(NODE_T * p)9789 mark_auxilliary (NODE_T * p)
9790 {
9791   for (; p != NO_NODE; FORWARD (p)) {
9792     if (SUB (p) != NO_NODE) {
9793 /*
9794 You get no warnings on unused PROC parameters. That is ok since A68 has some
9795 parameters that you may not use at all - think of PROC (REF FILE) BOOL event
9796 routines in transput.
9797 */
9798       mark_auxilliary (SUB (p));
9799     } else if (IS (p, OPERATOR)) {
9800       TAG_T *z;
9801       if (TAX (p) != NO_TAG) {
9802         USE (TAX (p)) = A68_TRUE;
9803       }
9804       if ((z = find_tag_global (TABLE (p), PRIO_SYMBOL, NSYMBOL (p))) != NO_TAG) {
9805         USE (z) = A68_TRUE;
9806       }
9807     } else if (IS (p, INDICANT)) {
9808       TAG_T *z = find_tag_global (TABLE (p), INDICANT, NSYMBOL (p));
9809       if (z != NO_TAG) {
9810         TAX (p) = z;
9811         USE (z) = A68_TRUE;
9812       }
9813     } else if (IS (p, IDENTIFIER)) {
9814       if (TAX (p) != NO_TAG) {
9815         USE (TAX (p)) = A68_TRUE;
9816       }
9817     }
9818   }
9819 }
9820 
9821 /**
9822 @brief Check a single tag.
9823 @param s Tag to check.
9824 **/
9825 
9826 static void
unused(TAG_T * s)9827 unused (TAG_T * s)
9828 {
9829   for (; s != NO_TAG; FORWARD (s)) {
9830     if (LINE_NUMBER (NODE (s)) > 0 && !USE (s)) {
9831       diagnostic_node (A68_WARNING, NODE (s), WARNING_TAG_UNUSED, NODE (s));
9832     }
9833   }
9834 }
9835 
9836 /**
9837 @brief Driver for traversing tree and warn for unused tags.
9838 @param p Node in syntax tree.
9839 **/
9840 
9841 void
warn_for_unused_tags(NODE_T * p)9842 warn_for_unused_tags (NODE_T * p)
9843 {
9844   for (; p != NO_NODE; FORWARD (p)) {
9845     if (SUB (p) != NO_NODE) {
9846       if (is_new_lexical_level (p) && ATTRIBUTE (TABLE (SUB (p))) != ENVIRON_SYMBOL) {
9847         unused (OPERATORS (TABLE (SUB (p))));
9848         unused (PRIO (TABLE (SUB (p))));
9849         unused (IDENTIFIERS (TABLE (SUB (p))));
9850         unused (LABELS (TABLE (SUB (p))));
9851         unused (INDICANTS (TABLE (SUB (p))));
9852       }
9853     }
9854     warn_for_unused_tags (SUB (p));
9855   }
9856 }
9857 
9858 /**
9859 @brief Mark jumps and procedured jumps.
9860 @param p Node in syntax tree.
9861 **/
9862 
9863 void
jumps_from_procs(NODE_T * p)9864 jumps_from_procs (NODE_T * p)
9865 {
9866   for (; p != NO_NODE; FORWARD (p)) {
9867     if (IS (p, PROCEDURING)) {
9868       NODE_T *u = SUB_SUB (p);
9869       if (IS (u, GOTO_SYMBOL)) {
9870         FORWARD (u);
9871       }
9872       USE (TAX (u)) = A68_TRUE;
9873     } else if (IS (p, JUMP)) {
9874       NODE_T *u = SUB (p);
9875       if (IS (u, GOTO_SYMBOL)) {
9876         FORWARD (u);
9877       }
9878       if ((TAX (u) == NO_TAG) && (MOID (u) == NO_MOID) && (find_tag_global (TABLE (u), LABEL, NSYMBOL (u)) == NO_TAG)) {
9879         (void) add_tag (TABLE (u), LABEL, u, NO_MOID, LOCAL_LABEL);
9880         diagnostic_node (A68_ERROR, u, ERROR_UNDECLARED_TAG);
9881       } else {
9882         USE (TAX (u)) = A68_TRUE;
9883       }
9884     } else {
9885       jumps_from_procs (SUB (p));
9886     }
9887   }
9888 }
9889 
9890 /**
9891 @brief Assign offset tags.
9892 @param t Tag to start from.
9893 @param base First (base) address.
9894 @return End address.
9895 **/
9896 
9897 static ADDR_T
assign_offset_tags(TAG_T * t,ADDR_T base)9898 assign_offset_tags (TAG_T * t, ADDR_T base)
9899 {
9900   ADDR_T sum = base;
9901   for (; t != NO_TAG; FORWARD (t)) {
9902     ABEND (MOID (t) == NO_MOID, "tag has no mode", NSYMBOL (NODE (t)));
9903     SIZE (t) = moid_size (MOID (t));
9904     if (VALUE (t) == NO_TEXT) {
9905       OFFSET (t) = sum;
9906       sum += SIZE (t);
9907     }
9908   }
9909   return (sum);
9910 }
9911 
9912 /**
9913 @brief Assign offsets table.
9914 @param c Symbol table .
9915 **/
9916 
9917 void
assign_offsets_table(TABLE_T * c)9918 assign_offsets_table (TABLE_T * c)
9919 {
9920   AP_INCREMENT (c) = assign_offset_tags (IDENTIFIERS (c), 0);
9921   AP_INCREMENT (c) = assign_offset_tags (OPERATORS (c), AP_INCREMENT (c));
9922   AP_INCREMENT (c) = assign_offset_tags (ANONYMOUS (c), AP_INCREMENT (c));
9923   AP_INCREMENT (c) = A68_ALIGN (AP_INCREMENT (c));
9924 }
9925 
9926 /**
9927 @brief Assign offsets.
9928 @param p Node in syntax tree.
9929 **/
9930 
9931 void
assign_offsets(NODE_T * p)9932 assign_offsets (NODE_T * p)
9933 {
9934   for (; p != NO_NODE; FORWARD (p)) {
9935     if (SUB (p) != NO_NODE && is_new_lexical_level (p)) {
9936       assign_offsets_table (TABLE (SUB (p)));
9937     }
9938     assign_offsets (SUB (p));
9939   }
9940 }
9941 
9942 /**
9943 @brief Assign offsets packs in moid list.
9944 @param q Moid to start from.
9945 **/
9946 
9947 void
assign_offsets_packs(MOID_T * q)9948 assign_offsets_packs (MOID_T * q)
9949 {
9950   for (; q != NO_MOID; FORWARD (q)) {
9951     if (EQUIVALENT (q) == NO_MOID && IS (q, STRUCT_SYMBOL)) {
9952       PACK_T *p = PACK (q);
9953       ADDR_T offset = 0;
9954       for (; p != NO_PACK; FORWARD (p)) {
9955         SIZE (p) = moid_size (MOID (p));
9956         OFFSET (p) = offset;
9957         offset += SIZE (p);
9958       }
9959     }
9960   }
9961 }
9962 
9963 /**************************************/
9964 /* MODE checker and coercion inserter */
9965 /**************************************/
9966 
9967 
9968 /**
9969 @brief Give accurate error message.
9970 @param n Node in syntax tree.
9971 @param p Mode 1.
9972 @param q Mode 2.
9973 @param context Context.
9974 @param deflex Deflexing regime.
9975 @param depth Depth of recursion.
9976 @return Error text.
9977 **/
9978 
9979 static char *
mode_error_text(NODE_T * n,MOID_T * p,MOID_T * q,int context,int deflex,int depth)9980 mode_error_text (NODE_T * n, MOID_T * p, MOID_T * q, int context, int deflex, int depth)
9981 {
9982 #define TAIL(z) (&(z)[strlen (z)])
9983   static char txt[BUFFER_SIZE];
9984   if (depth == 1) {
9985     txt[0] = NULL_CHAR;
9986   }
9987   if (IS (p, SERIES_MODE)) {
9988     PACK_T *u = PACK (p);
9989     if (u == NO_PACK) {
9990       ASSERT (snprintf (txt, SNPRINTF_SIZE, "empty mode-list") >= 0);
9991     } else {
9992       for (; u != NO_PACK; FORWARD (u)) {
9993         if (MOID (u) != NO_MOID) {
9994           if (IS (MOID (u), SERIES_MODE)) {
9995             (void) mode_error_text (n, MOID (u), q, context, deflex, depth + 1);
9996           } else if (!is_coercible (MOID (u), q, context, deflex)) {
9997             int len = (int) strlen (txt);
9998             if (len > BUFFER_SIZE / 2) {
9999               ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " etcetera") >= 0);
10000             } else {
10001               if (strlen (txt) > 0) {
10002                 ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " and ") >= 0);
10003               }
10004               ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, "%s", moid_to_string (MOID (u), MOID_ERROR_WIDTH, n)) >= 0);
10005             }
10006           }
10007         }
10008       }
10009     }
10010     if (depth == 1) {
10011       ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " cannot be coerced to %s", moid_to_string (q, MOID_ERROR_WIDTH, n)) >= 0);
10012     }
10013   } else if (IS (p, STOWED_MODE) && IS (q, FLEX_SYMBOL)) {
10014     PACK_T *u = PACK (p);
10015     if (u == NO_PACK) {
10016       ASSERT (snprintf (txt, SNPRINTF_SIZE, "empty mode-list") >= 0);
10017     } else {
10018       for (; u != NO_PACK; FORWARD (u)) {
10019         if (!is_coercible (MOID (u), SLICE (SUB (q)), context, deflex)) {
10020           int len = (int) strlen (txt);
10021           if (len > BUFFER_SIZE / 2) {
10022             ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " etcetera") >= 0);
10023           } else {
10024             if (strlen (txt) > 0) {
10025               ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " and ") >= 0);
10026             }
10027             ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, "%s", moid_to_string (MOID (u), MOID_ERROR_WIDTH, n)) >= 0);
10028           }
10029         }
10030       }
10031       ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " cannot be coerced to %s", moid_to_string (SLICE (SUB (q)), MOID_ERROR_WIDTH, n)) >= 0);
10032     }
10033   } else if (IS (p, STOWED_MODE) && IS (q, ROW_SYMBOL)) {
10034     PACK_T *u = PACK (p);
10035     if (u == NO_PACK) {
10036       ASSERT (snprintf (txt, SNPRINTF_SIZE, "empty mode-list") >= 0);
10037     } else {
10038       for (; u != NO_PACK; FORWARD (u)) {
10039         if (!is_coercible (MOID (u), SLICE (q), context, deflex)) {
10040           int len = (int) strlen (txt);
10041           if (len > BUFFER_SIZE / 2) {
10042             ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " etcetera") >= 0);
10043           } else {
10044             if (strlen (txt) > 0) {
10045               ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " and ") >= 0);
10046             }
10047             ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, "%s", moid_to_string (MOID (u), MOID_ERROR_WIDTH, n)) >= 0);
10048           }
10049         }
10050       }
10051       ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " cannot be coerced to %s", moid_to_string (SLICE (q), MOID_ERROR_WIDTH, n)) >= 0);
10052     }
10053   } else if (IS (p, STOWED_MODE) && (IS (q, PROC_SYMBOL) || IS (q, STRUCT_SYMBOL))) {
10054     PACK_T *u = PACK (p), *v = PACK (q);
10055     if (u == NO_PACK) {
10056       ASSERT (snprintf (txt, SNPRINTF_SIZE, "empty mode-list") >= 0);
10057     } else {
10058       for (; u != NO_PACK && v != NO_PACK; FORWARD (u), FORWARD (v)) {
10059         if (!is_coercible (MOID (u), MOID (v), context, deflex)) {
10060           int len = (int) strlen (txt);
10061           if (len > BUFFER_SIZE / 2) {
10062             ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " etcetera") >= 0);
10063           } else {
10064             if (strlen (txt) > 0) {
10065               ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, " and ") >= 0);
10066             }
10067             ASSERT (snprintf (TAIL (txt), SNPRINTF_SIZE, "%s cannot be coerced to %s", moid_to_string (MOID (u), MOID_ERROR_WIDTH, n), moid_to_string (MOID (v), MOID_ERROR_WIDTH, n)) >= 0);
10068           }
10069         }
10070       }
10071     }
10072   }
10073   return (txt);
10074 #undef TAIL
10075 }
10076 
10077 /**
10078 @brief Cannot coerce error.
10079 @param p Node in syntax tree.
10080 @param from Mode 1.
10081 @param to Mode 2.
10082 @param context Context.
10083 @param deflex Deflexing regime.
10084 @param att Attribute of context.
10085 **/
10086 
10087 static void
cannot_coerce(NODE_T * p,MOID_T * from,MOID_T * to,int context,int deflex,int att)10088 cannot_coerce (NODE_T * p, MOID_T * from, MOID_T * to, int context, int deflex, int att)
10089 {
10090   char *txt = mode_error_text (p, from, to, context, deflex, 1);
10091   if (att == STOP) {
10092     if (strlen (txt) == 0) {
10093       diagnostic_node (A68_ERROR, p, "M cannot be coerced to M in C context", from, to, context);
10094     } else {
10095       diagnostic_node (A68_ERROR, p, "Y in C context", txt, context);
10096     }
10097   } else {
10098     if (strlen (txt) == 0) {
10099       diagnostic_node (A68_ERROR, p, "M cannot be coerced to M in C-A", from, to, context, att);
10100     } else {
10101       diagnostic_node (A68_ERROR, p, "Y in C-A", txt, context, att);
10102     }
10103   }
10104 }
10105 
10106 /**
10107 @brief Make SOID data structure.
10108 @param s Soid buffer.
10109 @param sort Sort.
10110 @param type Mode.
10111 @param attribute Attribute.
10112 **/
10113 
10114 static void
make_soid(SOID_T * s,int sort,MOID_T * type,int attribute)10115 make_soid (SOID_T * s, int sort, MOID_T * type, int attribute)
10116 {
10117   ATTRIBUTE (s) = attribute;
10118   SORT (s) = sort;
10119   MOID (s) = type;
10120   CAST (s) = A68_FALSE;
10121 }
10122 
10123 /**
10124 @brief Driver for mode checker.
10125 @param p Node in syntax tree.
10126 **/
10127 
10128 void
mode_checker(NODE_T * p)10129 mode_checker (NODE_T * p)
10130 {
10131   if (IS (p, PARTICULAR_PROGRAM)) {
10132     SOID_T x, y;
10133     top_soid_list = NO_SOID;
10134     make_soid (&x, STRONG, MODE (VOID), 0);
10135     mode_check_enclosed (SUB (p), &x, &y);
10136     MOID (p) = MOID (&y);
10137   }
10138 }
10139 
10140 /**
10141 @brief Driver for coercion inserions.
10142 @param p Node in syntax tree.
10143 **/
10144 
10145 void
coercion_inserter(NODE_T * p)10146 coercion_inserter (NODE_T * p)
10147 {
10148   if (IS (p, PARTICULAR_PROGRAM)) {
10149     SOID_T q;
10150     make_soid (&q, STRONG, MODE (VOID), 0);
10151     coerce_enclosed (SUB (p), &q);
10152   }
10153 }
10154 
10155 /**
10156 @brief Whether mode is not well defined.
10157 @param p Mode.
10158 @return See brief description.
10159 **/
10160 
10161 static BOOL_T
is_mode_isnt_well(MOID_T * p)10162 is_mode_isnt_well (MOID_T * p)
10163 {
10164   if (p == NO_MOID) {
10165     return (A68_TRUE);
10166   } else if (!IF_MODE_IS_WELL (p)) {
10167     return (A68_TRUE);
10168   } else if (PACK (p) != NO_PACK) {
10169     PACK_T *q = PACK (p);
10170     for (; q != NO_PACK; FORWARD (q)) {
10171       if (!IF_MODE_IS_WELL (MOID (q))) {
10172         return (A68_TRUE);
10173       }
10174     }
10175   }
10176   return (A68_FALSE);
10177 }
10178 
10179 /**
10180 @brief Add SOID data to free chain.
10181 @param root Top soid list.
10182 **/
10183 
10184 void
free_soid_list(SOID_T * root)10185 free_soid_list (SOID_T * root)
10186 {
10187   if (root != NO_SOID) {
10188     SOID_T *q;
10189     for (q = root; NEXT (q) != NO_SOID; FORWARD (q)) {
10190       /* skip */ ;
10191     }
10192     NEXT (q) = top_soid_list;
10193     top_soid_list = root;
10194   }
10195 }
10196 
10197 /**
10198 @brief Add SOID data structure to soid list.
10199 @param root Top soid list.
10200 @param where Node in syntax tree.
10201 @param soid Entry to add.
10202 **/
10203 
10204 static void
add_to_soid_list(SOID_T ** root,NODE_T * where,SOID_T * soid)10205 add_to_soid_list (SOID_T ** root, NODE_T * where, SOID_T * soid)
10206 {
10207   if (*root != NO_SOID) {
10208     add_to_soid_list (&(NEXT (*root)), where, soid);
10209   } else {
10210     SOID_T *new_one;
10211     if (top_soid_list == NO_SOID) {
10212       new_one = (SOID_T *) get_temp_heap_space ((size_t) SIZE_AL (SOID_T));
10213     } else {
10214       new_one = top_soid_list;
10215       FORWARD (top_soid_list);
10216     }
10217     make_soid (new_one, SORT (soid), MOID (soid), 0);
10218     NODE (new_one) = where;
10219     NEXT (new_one) = NO_SOID;
10220     *root = new_one;
10221   }
10222 }
10223 
10224 /**
10225 @brief Pack soids in moid, gather resulting moids from terminators in a clause.
10226 @param top_sl Top soid list.
10227 @param attribute Mode attribute.
10228 @return Mode table entry.
10229 **/
10230 
10231 static MOID_T *
pack_soids_in_moid(SOID_T * top_sl,int attribute)10232 pack_soids_in_moid (SOID_T * top_sl, int attribute)
10233 {
10234   MOID_T *x = new_moid ();
10235   PACK_T *t, **p;
10236   ATTRIBUTE (x) = attribute;
10237   DIM (x) = 0;
10238   SUB (x) = NO_MOID;
10239   EQUIVALENT (x) = NO_MOID;
10240   SLICE (x) = NO_MOID;
10241   DEFLEXED (x) = NO_MOID;
10242   NAME (x) = NO_MOID;
10243   NEXT (x) = NO_MOID;
10244   PACK (x) = NO_PACK;
10245   p = &(PACK (x));
10246   for (; top_sl != NO_SOID; FORWARD (top_sl)) {
10247     t = new_pack ();
10248     MOID (t) = MOID (top_sl);
10249     TEXT (t) = NO_TEXT;
10250     NODE (t) = NODE (top_sl);
10251     NEXT (t) = NO_PACK;
10252     DIM (x)++;
10253     *p = t;
10254     p = &NEXT (t);
10255   }
10256   (void) register_extra_mode (&TOP_MOID (&program), x);
10257   return (x);
10258 }
10259 
10260 /**
10261 @brief Whether "p" is compatible with "q".
10262 @param p Mode.
10263 @param q Mode.
10264 @param deflex Deflexing regime.
10265 @return See brief description.
10266 **/
10267 
10268 static BOOL_T
is_equal_modes(MOID_T * p,MOID_T * q,int deflex)10269 is_equal_modes (MOID_T * p, MOID_T * q, int deflex)
10270 {
10271   if (deflex == FORCE_DEFLEXING) {
10272     return (DEFLEX (p) == DEFLEX (q));
10273   } else if (deflex == ALIAS_DEFLEXING) {
10274     if (IS (p, REF_SYMBOL) && IS (q, REF_SYMBOL)) {
10275       return (p == q || DEFLEX (p) == q);
10276     } else if (ISNT (p, REF_SYMBOL) && ISNT (q, REF_SYMBOL)) {
10277       return (DEFLEX (p) == DEFLEX (q));
10278     }
10279   } else if (deflex == SAFE_DEFLEXING) {
10280     if (ISNT (p, REF_SYMBOL) && ISNT (q, REF_SYMBOL)) {
10281       return (DEFLEX (p) == DEFLEX (q));
10282     }
10283   }
10284   return (p == q);
10285 }
10286 
10287 /**
10288 @brief Whether mode is deprefable.
10289 @param p Mode.
10290 @return See brief description.
10291 **/
10292 
10293 BOOL_T
is_deprefable(MOID_T * p)10294 is_deprefable (MOID_T * p)
10295 {
10296   if (IS (p, REF_SYMBOL)) {
10297     return (A68_TRUE);
10298   } else {
10299     return ((BOOL_T) (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK));
10300   }
10301 }
10302 
10303 /**
10304 @brief Depref mode once.
10305 @param p Mode.
10306 @return Single-depreffed mode.
10307 **/
10308 
10309 static MOID_T *
depref_once(MOID_T * p)10310 depref_once (MOID_T * p)
10311 {
10312   if (IS_REF_FLEX (p)) {
10313     return (SUB_SUB (p));
10314   } else if (IS (p, REF_SYMBOL)) {
10315     return (SUB (p));
10316   } else if (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
10317     return (SUB (p));
10318   } else {
10319     return (NO_MOID);
10320   }
10321 }
10322 
10323 /**
10324 @brief Depref mode completely.
10325 @param p Mode.
10326 @return Completely depreffed mode.
10327 **/
10328 
10329 MOID_T *
depref_completely(MOID_T * p)10330 depref_completely (MOID_T * p)
10331 {
10332   while (is_deprefable (p)) {
10333     p = depref_once (p);
10334   }
10335   return (p);
10336 }
10337 
10338 /**
10339 @brief Deproc_completely.
10340 @param p Mode.
10341 @return Completely deprocedured mode.
10342 **/
10343 
10344 static MOID_T *
deproc_completely(MOID_T * p)10345 deproc_completely (MOID_T * p)
10346 {
10347   while (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
10348     p = depref_once (p);
10349   }
10350   return (p);
10351 }
10352 
10353 /**
10354 @brief Depref rows.
10355 @param p Mode.
10356 @param q Mode.
10357 @return Possibly depreffed mode.
10358 **/
10359 
10360 static MOID_T *
depref_rows(MOID_T * p,MOID_T * q)10361 depref_rows (MOID_T * p, MOID_T * q)
10362 {
10363   if (q == MODE (ROWS)) {
10364     while (is_deprefable (p)) {
10365       p = depref_once (p);
10366     }
10367     return (p);
10368   } else {
10369     return (q);
10370   }
10371 }
10372 
10373 /**
10374 @brief Derow mode, strip FLEX and BOUNDS.
10375 @param p Mode.
10376 @return See brief description.
10377 **/
10378 
10379 static MOID_T *
derow(MOID_T * p)10380 derow (MOID_T * p)
10381 {
10382   if (IS (p, ROW_SYMBOL) || IS (p, FLEX_SYMBOL)) {
10383     return (derow (SUB (p)));
10384   } else {
10385     return (p);
10386   }
10387 }
10388 
10389 /**
10390 @brief Whether rows type.
10391 @param p Mode.
10392 @return See brief description.
10393 **/
10394 
10395 static BOOL_T
is_rows_type(MOID_T * p)10396 is_rows_type (MOID_T * p)
10397 {
10398   switch (ATTRIBUTE (p)) {
10399   case ROW_SYMBOL:
10400   case FLEX_SYMBOL:
10401     {
10402       return (A68_TRUE);
10403     }
10404   case UNION_SYMBOL:
10405     {
10406       PACK_T *t = PACK (p);
10407       BOOL_T go_on = A68_TRUE;
10408       while (t != NO_PACK && go_on) {
10409         go_on &= is_rows_type (MOID (t));
10410         FORWARD (t);
10411       }
10412       return (go_on);
10413     }
10414   default:
10415     {
10416       return (A68_FALSE);
10417     }
10418   }
10419 }
10420 
10421 /**
10422 @brief Whether mode is PROC (REF FILE) VOID or FORMAT.
10423 @param p Mode.
10424 @return See brief description.
10425 **/
10426 
10427 static BOOL_T
is_proc_ref_file_void_or_format(MOID_T * p)10428 is_proc_ref_file_void_or_format (MOID_T * p)
10429 {
10430   if (p == MODE (PROC_REF_FILE_VOID)) {
10431     return (A68_TRUE);
10432   } else if (p == MODE (FORMAT)) {
10433     return (A68_TRUE);
10434   } else {
10435     return (A68_FALSE);
10436   }
10437 }
10438 
10439 /**
10440 @brief Whether mode can be transput.
10441 @param p Mode.
10442 @param rw Indicates Read or Write.
10443 @return See brief description.
10444 **/
10445 
10446 static BOOL_T
is_transput_mode(MOID_T * p,char rw)10447 is_transput_mode (MOID_T * p, char rw)
10448 {
10449   if (p == MODE (INT)) {
10450     return (A68_TRUE);
10451   } else if (p == MODE (LONG_INT)) {
10452     return (A68_TRUE);
10453   } else if (p == MODE (LONGLONG_INT)) {
10454     return (A68_TRUE);
10455   } else if (p == MODE (REAL)) {
10456     return (A68_TRUE);
10457   } else if (p == MODE (LONG_REAL)) {
10458     return (A68_TRUE);
10459   } else if (p == MODE (LONGLONG_REAL)) {
10460     return (A68_TRUE);
10461   } else if (p == MODE (BOOL)) {
10462     return (A68_TRUE);
10463   } else if (p == MODE (CHAR)) {
10464     return (A68_TRUE);
10465   } else if (p == MODE (BITS)) {
10466     return (A68_TRUE);
10467   } else if (p == MODE (LONG_BITS)) {
10468     return (A68_TRUE);
10469   } else if (p == MODE (LONGLONG_BITS)) {
10470     return (A68_TRUE);
10471   } else if (p == MODE (COMPLEX)) {
10472     return (A68_TRUE);
10473   } else if (p == MODE (LONG_COMPLEX)) {
10474     return (A68_TRUE);
10475   } else if (p == MODE (LONGLONG_COMPLEX)) {
10476     return (A68_TRUE);
10477   } else if (p == MODE (ROW_CHAR)) {
10478     return (A68_TRUE);
10479   } else if (p == MODE (STRING)) {
10480     return (A68_TRUE);
10481   } else if (p == MODE (SOUND)) {
10482     return (A68_TRUE);
10483   } else if (IS (p, UNION_SYMBOL) || IS (p, STRUCT_SYMBOL)) {
10484     PACK_T *q = PACK (p);
10485     BOOL_T k = A68_TRUE;
10486     for (; q != NO_PACK && k; FORWARD (q)) {
10487       k = (BOOL_T) (k & (is_transput_mode (MOID (q), rw) || is_proc_ref_file_void_or_format (MOID (q))));
10488     }
10489     return (k);
10490   } else if (IS (p, FLEX_SYMBOL)) {
10491     if (SUB (p) == MODE (ROW_CHAR)) {
10492       return (A68_TRUE);
10493     } else {
10494       return ((BOOL_T) (rw == 'w' ? is_transput_mode (SUB (p), rw) : A68_FALSE));
10495     }
10496   } else if (IS (p, ROW_SYMBOL)) {
10497     return ((BOOL_T) (is_transput_mode (SUB (p), rw) || is_proc_ref_file_void_or_format (SUB (p))));
10498   } else {
10499     return (A68_FALSE);
10500   }
10501 }
10502 
10503 /**
10504 @brief Whether mode is printable.
10505 @param p Mode.
10506 @return See brief description.
10507 **/
10508 
10509 static BOOL_T
is_printable_mode(MOID_T * p)10510 is_printable_mode (MOID_T * p)
10511 {
10512   if (is_proc_ref_file_void_or_format (p)) {
10513     return (A68_TRUE);
10514   } else {
10515     return (is_transput_mode (p, 'w'));
10516   }
10517 }
10518 
10519 /**
10520 @brief Whether mode is readable.
10521 @param p Mode.
10522 @return See brief description.
10523 **/
10524 
10525 static BOOL_T
is_readable_mode(MOID_T * p)10526 is_readable_mode (MOID_T * p)
10527 {
10528   if (is_proc_ref_file_void_or_format (p)) {
10529     return (A68_TRUE);
10530   } else {
10531     return ((BOOL_T) (IS (p, REF_SYMBOL) ? is_transput_mode (SUB (p), 'r') : A68_FALSE));
10532   }
10533 }
10534 
10535 /**
10536 @brief Whether name struct.
10537 @param p Mode.
10538 @return See brief description.
10539 **/
10540 
10541 static BOOL_T
is_name_struct(MOID_T * p)10542 is_name_struct (MOID_T * p)
10543 {
10544   return ((BOOL_T) (NAME (p) != NO_MOID ? IS (DEFLEX (SUB (p)), STRUCT_SYMBOL) : A68_FALSE));
10545 }
10546 
10547 /**
10548 @brief Yield mode to unite to.
10549 @param m Mode.
10550 @param u United mode.
10551 @return See brief description.
10552 **/
10553 
10554 MOID_T *
unites_to(MOID_T * m,MOID_T * u)10555 unites_to (MOID_T * m, MOID_T * u)
10556 {
10557 /* Uniting U (m) */
10558   MOID_T *v = NO_MOID;
10559   PACK_T *p;
10560   if (u == MODE (SIMPLIN) || u == MODE (SIMPLOUT)) {
10561     return (m);
10562   }
10563   for (p = PACK (u); p != NO_PACK; FORWARD (p)) {
10564 /* Prefer []->[] over []->FLEX [] */
10565     if (m == MOID (p)) {
10566       v = MOID (p);
10567     } else if (v == NO_MOID && DEFLEX (m) == DEFLEX (MOID (p))) {
10568       v = MOID (p);
10569     }
10570   }
10571   return (v);
10572 }
10573 
10574 /**
10575 @brief Whether moid in pack.
10576 @param u Mode.
10577 @param v Pack.
10578 @param deflex Deflexing regime.
10579 @return See brief description.
10580 **/
10581 
10582 static BOOL_T
is_moid_in_pack(MOID_T * u,PACK_T * v,int deflex)10583 is_moid_in_pack (MOID_T * u, PACK_T * v, int deflex)
10584 {
10585   for (; v != NO_PACK; FORWARD (v)) {
10586     if (is_equal_modes (u, MOID (v), deflex)) {
10587       return (A68_TRUE);
10588     }
10589   }
10590   return (A68_FALSE);
10591 }
10592 
10593 /**
10594 @brief Whether "p" is a subset of "q".
10595 @param p Mode.
10596 @param q Mode.
10597 @param deflex Deflexing regime.
10598 @return See brief description.
10599 **/
10600 
10601 BOOL_T
is_subset(MOID_T * p,MOID_T * q,int deflex)10602 is_subset (MOID_T * p, MOID_T * q, int deflex)
10603 {
10604   PACK_T *u = PACK (p);
10605   BOOL_T j = A68_TRUE;
10606   for (; u != NO_PACK && j; FORWARD (u)) {
10607     j = (BOOL_T) (j && is_moid_in_pack (MOID (u), PACK (q), deflex));
10608   }
10609   return (j);
10610 }
10611 
10612 /**
10613 @brief Whether "p" can be united to UNION "q".
10614 @param p Mode.
10615 @param q Mode.
10616 @param deflex Deflexing regime.
10617 @return See brief description.
10618 **/
10619 
10620 BOOL_T
is_unitable(MOID_T * p,MOID_T * q,int deflex)10621 is_unitable (MOID_T * p, MOID_T * q, int deflex)
10622 {
10623   if (IS (q, UNION_SYMBOL)) {
10624     if (IS (p, UNION_SYMBOL)) {
10625       return (is_subset (p, q, deflex));
10626     } else {
10627       return (is_moid_in_pack (p, PACK (q), deflex));
10628     }
10629   }
10630   return (A68_FALSE);
10631 }
10632 
10633 /**
10634 @brief Whether all or some components of "u" can be firmly coerced to a component mode of "v"..
10635 @param u Mode.
10636 @param v Mode .
10637 @param all All coercible.
10638 @param some Some coercible.
10639 **/
10640 
10641 static void
investigate_firm_relations(PACK_T * u,PACK_T * v,BOOL_T * all,BOOL_T * some)10642 investigate_firm_relations (PACK_T * u, PACK_T * v, BOOL_T * all, BOOL_T * some)
10643 {
10644   *all = A68_TRUE;
10645   *some = A68_FALSE;
10646   for (; v != NO_PACK; FORWARD (v)) {
10647     PACK_T *w;
10648     BOOL_T k = A68_FALSE;
10649     for (w = u; w != NO_PACK; FORWARD (w)) {
10650       k |= is_coercible (MOID (w), MOID (v), FIRM, FORCE_DEFLEXING);
10651     }
10652     *some |= k;
10653     *all &= k;
10654   }
10655 }
10656 
10657 /**
10658 @brief Whether there is a soft path from "p" to "q".
10659 @param p Mode.
10660 @param q Mode.
10661 @param deflex Deflexing regime.
10662 @return See brief description.
10663 **/
10664 
10665 static BOOL_T
is_softly_coercible(MOID_T * p,MOID_T * q,int deflex)10666 is_softly_coercible (MOID_T * p, MOID_T * q, int deflex)
10667 {
10668   if (is_equal_modes (p, q, deflex)) {
10669     return (A68_TRUE);
10670   } else if (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
10671     return (is_softly_coercible (SUB (p), q, deflex));
10672   } else {
10673     return (A68_FALSE);
10674   }
10675 }
10676 
10677 /**
10678 @brief Whether there is a weak path from "p" to "q".
10679 @param p Mode.
10680 @param q Mode.
10681 @param deflex Deflexing regime.
10682 @return See brief description.
10683 **/
10684 
10685 static BOOL_T
is_weakly_coercible(MOID_T * p,MOID_T * q,int deflex)10686 is_weakly_coercible (MOID_T * p, MOID_T * q, int deflex)
10687 {
10688   if (is_equal_modes (p, q, deflex)) {
10689     return (A68_TRUE);
10690   } else if (is_deprefable (p)) {
10691     return (is_weakly_coercible (depref_once (p), q, deflex));
10692   } else {
10693     return (A68_FALSE);
10694   }
10695 }
10696 
10697 /**
10698 @brief Whether there is a meek path from "p" to "q".
10699 @param p Mode.
10700 @param q Mode.
10701 @param deflex Deflexing regime.
10702 @return See brief description.
10703 **/
10704 
10705 static BOOL_T
is_meekly_coercible(MOID_T * p,MOID_T * q,int deflex)10706 is_meekly_coercible (MOID_T * p, MOID_T * q, int deflex)
10707 {
10708   if (is_equal_modes (p, q, deflex)) {
10709     return (A68_TRUE);
10710   } else if (is_deprefable (p)) {
10711     return (is_meekly_coercible (depref_once (p), q, deflex));
10712   } else {
10713     return (A68_FALSE);
10714   }
10715 }
10716 
10717 /**
10718 @brief Whether there is a firm path from "p" to "q".
10719 @param p Mode.
10720 @param q Mode.
10721 @param deflex Deflexing regime.
10722 @return See brief description.
10723 **/
10724 
10725 static BOOL_T
is_firmly_coercible(MOID_T * p,MOID_T * q,int deflex)10726 is_firmly_coercible (MOID_T * p, MOID_T * q, int deflex)
10727 {
10728   if (is_equal_modes (p, q, deflex)) {
10729     return (A68_TRUE);
10730   } else if (q == MODE (ROWS) && is_rows_type (p)) {
10731     return (A68_TRUE);
10732   } else if (is_unitable (p, q, deflex)) {
10733     return (A68_TRUE);
10734   } else if (is_deprefable (p)) {
10735     return (is_firmly_coercible (depref_once (p), q, deflex));
10736   } else {
10737     return (A68_FALSE);
10738   }
10739 }
10740 
10741 /**
10742 @brief Whether "p" widens to "q".
10743 @param p Mode.
10744 @param q Mode.
10745 @return See brief description.
10746 **/
10747 
10748 static MOID_T *
widens_to(MOID_T * p,MOID_T * q)10749 widens_to (MOID_T * p, MOID_T * q)
10750 {
10751   if (p == MODE (INT)) {
10752     if (q == MODE (LONG_INT) || q == MODE (LONGLONG_INT) || q == MODE (LONG_REAL) || q == MODE (LONGLONG_REAL) || q == MODE (LONG_COMPLEX) || q == MODE (LONGLONG_COMPLEX)) {
10753       return (MODE (LONG_INT));
10754     } else if (q == MODE (REAL) || q == MODE (COMPLEX)) {
10755       return (MODE (REAL));
10756     } else {
10757       return (NO_MOID);
10758     }
10759   } else if (p == MODE (LONG_INT)) {
10760     if (q == MODE (LONGLONG_INT)) {
10761       return (MODE (LONGLONG_INT));
10762     } else if (q == MODE (LONG_REAL) || q == MODE (LONGLONG_REAL) || q == MODE (LONG_COMPLEX) || q == MODE (LONGLONG_COMPLEX)) {
10763       return (MODE (LONG_REAL));
10764     } else {
10765       return (NO_MOID);
10766     }
10767   } else if (p == MODE (LONGLONG_INT)) {
10768     if (q == MODE (LONGLONG_REAL) || q == MODE (LONGLONG_COMPLEX)) {
10769       return (MODE (LONGLONG_REAL));
10770     } else {
10771       return (NO_MOID);
10772     }
10773   } else if (p == MODE (REAL)) {
10774     if (q == MODE (LONG_REAL) || q == MODE (LONGLONG_REAL) || q == MODE (LONG_COMPLEX) || q == MODE (LONGLONG_COMPLEX)) {
10775       return (MODE (LONG_REAL));
10776     } else if (q == MODE (COMPLEX)) {
10777       return (MODE (COMPLEX));
10778     } else {
10779       return (NO_MOID);
10780     }
10781   } else if (p == MODE (COMPLEX)) {
10782     if (q == MODE (LONG_COMPLEX) || q == MODE (LONGLONG_COMPLEX)) {
10783       return (MODE (LONG_COMPLEX));
10784     } else {
10785       return (NO_MOID);
10786     }
10787   } else if (p == MODE (LONG_REAL)) {
10788     if (q == MODE (LONGLONG_REAL) || q == MODE (LONGLONG_COMPLEX)) {
10789       return (MODE (LONGLONG_REAL));
10790     } else if (q == MODE (LONG_COMPLEX)) {
10791       return (MODE (LONG_COMPLEX));
10792     } else {
10793       return (NO_MOID);
10794     }
10795   } else if (p == MODE (LONG_COMPLEX)) {
10796     if (q == MODE (LONGLONG_COMPLEX)) {
10797       return (MODE (LONGLONG_COMPLEX));
10798     } else {
10799       return (NO_MOID);
10800     }
10801   } else if (p == MODE (LONGLONG_REAL)) {
10802     if (q == MODE (LONGLONG_COMPLEX)) {
10803       return (MODE (LONGLONG_COMPLEX));
10804     } else {
10805       return (NO_MOID);
10806     }
10807   } else if (p == MODE (BITS)) {
10808     if (q == MODE (LONG_BITS) || q == MODE (LONGLONG_BITS)) {
10809       return (MODE (LONG_BITS));
10810     } else if (q == MODE (ROW_BOOL)) {
10811       return (MODE (ROW_BOOL));
10812     } else if (q == MODE (FLEX_ROW_BOOL)) {
10813       return (MODE (FLEX_ROW_BOOL));
10814     } else {
10815       return (NO_MOID);
10816     }
10817   } else if (p == MODE (LONG_BITS)) {
10818     if (q == MODE (LONGLONG_BITS)) {
10819       return (MODE (LONGLONG_BITS));
10820     } else if (q == MODE (ROW_BOOL)) {
10821       return (MODE (ROW_BOOL));
10822     } else if (q == MODE (FLEX_ROW_BOOL)) {
10823       return (MODE (FLEX_ROW_BOOL));
10824     } else {
10825       return (NO_MOID);
10826     }
10827   } else if (p == MODE (LONGLONG_BITS)) {
10828     if (q == MODE (ROW_BOOL)) {
10829       return (MODE (ROW_BOOL));
10830     } else if (q == MODE (FLEX_ROW_BOOL)) {
10831       return (MODE (FLEX_ROW_BOOL));
10832     } else {
10833       return (NO_MOID);
10834     }
10835   } else if (p == MODE (BYTES) && q == MODE (ROW_CHAR)) {
10836     return (MODE (ROW_CHAR));
10837   } else if (p == MODE (LONG_BYTES) && q == MODE (ROW_CHAR)) {
10838     return (MODE (ROW_CHAR));
10839   } else if (p == MODE (BYTES) && q == MODE (FLEX_ROW_CHAR)) {
10840     return (MODE (FLEX_ROW_CHAR));
10841   } else if (p == MODE (LONG_BYTES) && q == MODE (FLEX_ROW_CHAR)) {
10842     return (MODE (FLEX_ROW_CHAR));
10843   } else {
10844     return (NO_MOID);
10845   }
10846 }
10847 
10848 /**
10849 @brief Whether "p" widens to "q".
10850 @param p Mode.
10851 @param q Mode.
10852 @return See brief description.
10853 **/
10854 
10855 static BOOL_T
is_widenable(MOID_T * p,MOID_T * q)10856 is_widenable (MOID_T * p, MOID_T * q)
10857 {
10858   MOID_T *z = widens_to (p, q);
10859   if (z != NO_MOID) {
10860     return ((BOOL_T) (z == q ? A68_TRUE : is_widenable (z, q)));
10861   } else {
10862     return (A68_FALSE);
10863   }
10864 }
10865 
10866 /**
10867 @brief Whether "p" is a REF ROW.
10868 @param p Mode.
10869 @return See brief description.
10870 **/
10871 
10872 static BOOL_T
is_ref_row(MOID_T * p)10873 is_ref_row (MOID_T * p)
10874 {
10875   return ((BOOL_T) (NAME (p) != NO_MOID ? IS (DEFLEX (SUB (p)), ROW_SYMBOL) : A68_FALSE));
10876 }
10877 
10878 /**
10879 @brief Whether strong name.
10880 @param p Mode.
10881 @param q Mode.
10882 @return See brief description.
10883 **/
10884 
10885 static BOOL_T
is_strong_name(MOID_T * p,MOID_T * q)10886 is_strong_name (MOID_T * p, MOID_T * q)
10887 {
10888   if (p == q) {
10889     return (A68_TRUE);
10890   } else if (is_ref_row (q)) {
10891     return (is_strong_name (p, NAME (q)));
10892   } else {
10893     return (A68_FALSE);
10894   }
10895 }
10896 
10897 /**
10898 @brief Whether strong slice.
10899 @param p Mode.
10900 @param q Mode.
10901 @return See brief description.
10902 **/
10903 
10904 static BOOL_T
is_strong_slice(MOID_T * p,MOID_T * q)10905 is_strong_slice (MOID_T * p, MOID_T * q)
10906 {
10907   if (p == q || is_widenable (p, q)) {
10908     return (A68_TRUE);
10909   } else if (SLICE (q) != NO_MOID) {
10910     return (is_strong_slice (p, SLICE (q)));
10911   } else if (IS (q, FLEX_SYMBOL)) {
10912     return (is_strong_slice (p, SUB (q)));
10913   } else if (is_ref_row (q)) {
10914     return (is_strong_name (p, q));
10915   } else {
10916     return (A68_FALSE);
10917   }
10918 }
10919 
10920 /**
10921 @brief Whether strongly coercible.
10922 @param p Mode.
10923 @param q Mode.
10924 @param deflex Deflexing regime.
10925 @return See brief description.
10926 **/
10927 
10928 static BOOL_T
is_strongly_coercible(MOID_T * p,MOID_T * q,int deflex)10929 is_strongly_coercible (MOID_T * p, MOID_T * q, int deflex)
10930 {
10931 /* Keep this sequence of statements */
10932   if (is_equal_modes (p, q, deflex)) {
10933     return (A68_TRUE);
10934   } else if (q == MODE (VOID)) {
10935     return (A68_TRUE);
10936   } else if ((q == MODE (SIMPLIN) || q == MODE (ROW_SIMPLIN)) && is_readable_mode (p)) {
10937     return (A68_TRUE);
10938   } else if (q == MODE (ROWS) && is_rows_type (p)) {
10939     return (A68_TRUE);
10940   } else if (is_unitable (p, derow (q), deflex)) {
10941     return (A68_TRUE);
10942   }
10943   if (is_ref_row (q) && is_strong_name (p, q)) {
10944     return (A68_TRUE);
10945   } else if (SLICE (q) != NO_MOID && is_strong_slice (p, q)) {
10946     return (A68_TRUE);
10947   } else if (IS (q, FLEX_SYMBOL) && is_strong_slice (p, q)) {
10948     return (A68_TRUE);
10949   } else if (is_widenable (p, q)) {
10950     return (A68_TRUE);
10951   } else if (is_deprefable (p)) {
10952     return (is_strongly_coercible (depref_once (p), q, deflex));
10953   } else if (q == MODE (SIMPLOUT) || q == MODE (ROW_SIMPLOUT)) {
10954     return (is_printable_mode (p));
10955   } else {
10956     return (A68_FALSE);
10957   }
10958 }
10959 
10960 /**
10961 @brief Whether firm.
10962 @param p Mode.
10963 @param q Mode.
10964 @return See brief description.
10965 **/
10966 
10967 BOOL_T
is_firm(MOID_T * p,MOID_T * q)10968 is_firm (MOID_T * p, MOID_T * q)
10969 {
10970   return ((BOOL_T) (is_firmly_coercible (p, q, SAFE_DEFLEXING) || is_firmly_coercible (q, p, SAFE_DEFLEXING)));
10971 }
10972 
10973 /**
10974 @brief Whether coercible stowed.
10975 @param p Mode.
10976 @param q Mode.
10977 @param c Context.
10978 @param deflex Deflexing regime.
10979 @return See brief description.
10980 **/
10981 
10982 static BOOL_T
is_coercible_stowed(MOID_T * p,MOID_T * q,int c,int deflex)10983 is_coercible_stowed (MOID_T * p, MOID_T * q, int c, int deflex)
10984 {
10985   if (c == STRONG) {
10986     if (q == MODE (VOID)) {
10987       return (A68_TRUE);
10988     } else if (IS (q, FLEX_SYMBOL)) {
10989       PACK_T *u = PACK (p);
10990       BOOL_T j = A68_TRUE;
10991       for (; u != NO_PACK && j; FORWARD (u)) {
10992         j &= is_coercible (MOID (u), SLICE (SUB (q)), c, deflex);
10993       }
10994       return (j);
10995     } else if (IS (q, ROW_SYMBOL)) {
10996       PACK_T *u = PACK (p);
10997       BOOL_T j = A68_TRUE;
10998       for (; u != NO_PACK && j; FORWARD (u)) {
10999         j &= is_coercible (MOID (u), SLICE (q), c, deflex);
11000       }
11001       return (j);
11002     } else if (IS (q, PROC_SYMBOL) || IS (q, STRUCT_SYMBOL)) {
11003       PACK_T *u = PACK (p), *v = PACK (q);
11004       if (DIM (p) != DIM (q)) {
11005         return (A68_FALSE);
11006       } else {
11007         BOOL_T j = A68_TRUE;
11008         while (u != NO_PACK && v != NO_PACK && j) {
11009           j &= is_coercible (MOID (u), MOID (v), c, deflex);
11010           FORWARD (u);
11011           FORWARD (v);
11012         }
11013         return (j);
11014       }
11015     } else {
11016       return (A68_FALSE);
11017     }
11018   } else {
11019     return (A68_FALSE);
11020   }
11021 }
11022 
11023 /**
11024 @brief Whether coercible series.
11025 @param p Mode.
11026 @param q Mode.
11027 @param c Context.
11028 @param deflex Deflexing regime.
11029 @return See brief description.
11030 **/
11031 
11032 static BOOL_T
is_coercible_series(MOID_T * p,MOID_T * q,int c,int deflex)11033 is_coercible_series (MOID_T * p, MOID_T * q, int c, int deflex)
11034 {
11035   if (c != STRONG) {
11036     return (A68_FALSE);
11037   } else if (p == NO_MOID || q == NO_MOID) {
11038     return (A68_FALSE);
11039   } else if (IS (p, SERIES_MODE) && PACK (p) == NO_PACK) {
11040     return (A68_FALSE);
11041   } else if (IS (q, SERIES_MODE) && PACK (q) == NO_PACK) {
11042     return (A68_FALSE);
11043   } else if (PACK (p) == NO_PACK) {
11044     return (is_coercible (p, q, c, deflex));
11045   } else {
11046     PACK_T *u = PACK (p);
11047     BOOL_T j = A68_TRUE;
11048     for (; u != NO_PACK && j; FORWARD (u)) {
11049       if (MOID (u) != NO_MOID) {
11050         j &= is_coercible (MOID (u), q, c, deflex);
11051       }
11052     }
11053     return (j);
11054   }
11055 }
11056 
11057 /**
11058 @brief Basic coercions.
11059 @param p Mode.
11060 @param q Mode.
11061 @param c Context.
11062 @param deflex Deflexing regime.
11063 @return See brief description.
11064 **/
11065 
11066 static BOOL_T
basic_coercions(MOID_T * p,MOID_T * q,int c,int deflex)11067 basic_coercions (MOID_T * p, MOID_T * q, int c, int deflex)
11068 {
11069   if (is_equal_modes (p, q, deflex)) {
11070     return (A68_TRUE);
11071   } else if (c == NO_SORT) {
11072     return ((BOOL_T) (p == q));
11073   } else if (c == SOFT) {
11074     return (is_softly_coercible (p, q, deflex));
11075   } else if (c == WEAK) {
11076     return (is_weakly_coercible (p, q, deflex));
11077   } else if (c == MEEK) {
11078     return (is_meekly_coercible (p, q, deflex));
11079   } else if (c == FIRM) {
11080     return (is_firmly_coercible (p, q, deflex));
11081   } else if (c == STRONG) {
11082     return (is_strongly_coercible (p, q, deflex));
11083   } else {
11084     return (A68_FALSE);
11085   }
11086 }
11087 
11088 /**
11089 @brief Whether "p" can be coerced to "q" in a "c" context.
11090 @param p Mode.
11091 @param q Mode.
11092 @param c Context.
11093 @param deflex Deflexing regime.
11094 @return See brief description.
11095 **/
11096 
11097 BOOL_T
is_coercible(MOID_T * p,MOID_T * q,int c,int deflex)11098 is_coercible (MOID_T * p, MOID_T * q, int c, int deflex)
11099 {
11100   if (is_mode_isnt_well (p) || is_mode_isnt_well (q)) {
11101     return (A68_TRUE);
11102   } else if (is_equal_modes (p, q, deflex)) {
11103     return (A68_TRUE);
11104   } else if (p == MODE (HIP)) {
11105     return (A68_TRUE);
11106   } else if (IS (p, STOWED_MODE)) {
11107     return (is_coercible_stowed (p, q, c, deflex));
11108   } else if (IS (p, SERIES_MODE)) {
11109     return (is_coercible_series (p, q, c, deflex));
11110   } else if (p == MODE (VACUUM) && IS (DEFLEX (q), ROW_SYMBOL)) {
11111     return (A68_TRUE);
11112   } else {
11113     return (basic_coercions (p, q, c, deflex));
11114   }
11115 }
11116 
11117 /**
11118 @brief Whether coercible in context.
11119 @param p Soid.
11120 @param q Soid.
11121 @param deflex Deflexing regime.
11122 @return See brief description.
11123 **/
11124 
11125 static BOOL_T
is_coercible_in_context(SOID_T * p,SOID_T * q,int deflex)11126 is_coercible_in_context (SOID_T * p, SOID_T * q, int deflex)
11127 {
11128   if (SORT (p) != SORT (q)) {
11129     return (A68_FALSE);
11130   } else if (MOID (p) == MOID (q)) {
11131     return (A68_TRUE);
11132   } else {
11133     return (is_coercible (MOID (p), MOID (q), SORT (q), deflex));
11134   }
11135 }
11136 
11137 /**
11138 @brief Whether list "y" is balanced.
11139 @param n Node in syntax tree.
11140 @param y Soid list.
11141 @param sort Sort.
11142 @return See brief description.
11143 **/
11144 
11145 static BOOL_T
is_balanced(NODE_T * n,SOID_T * y,int sort)11146 is_balanced (NODE_T * n, SOID_T * y, int sort)
11147 {
11148   if (sort == STRONG) {
11149     return (A68_TRUE);
11150   } else {
11151     BOOL_T k = A68_FALSE;
11152     for (; y != NO_SOID && !k; FORWARD (y)) {
11153       k = (BOOL_T) (ISNT (MOID (y), STOWED_MODE));
11154     }
11155     if (k == A68_FALSE) {
11156       diagnostic_node (A68_ERROR, n, ERROR_NO_UNIQUE_MODE);
11157     }
11158     return (k);
11159   }
11160 }
11161 
11162 /**
11163 @brief A moid from "m" to which all other members can be coerced.
11164 @param m Mode.
11165 @param sort Sort.
11166 @param return_depreffed Whether to depref.
11167 @param deflex Deflexing regime.
11168 @return See brief description.
11169 **/
11170 
11171 MOID_T *
get_balanced_mode(MOID_T * m,int sort,BOOL_T return_depreffed,int deflex)11172 get_balanced_mode (MOID_T * m, int sort, BOOL_T return_depreffed, int deflex)
11173 {
11174   MOID_T *common = NO_MOID;
11175   if (m != NO_MOID && !is_mode_isnt_well (m) && IS (m, UNION_SYMBOL)) {
11176     int depref_level;
11177     BOOL_T go_on = A68_TRUE;
11178 /* Test for increasing depreffing */
11179     for (depref_level = 0; go_on; depref_level++) {
11180       PACK_T *p;
11181       go_on = A68_FALSE;
11182 /* Test the whole pack */
11183       for (p = PACK (m); p != NO_PACK; FORWARD (p)) {
11184 /* HIPs are not eligible of course */
11185         if (MOID (p) != MODE (HIP)) {
11186           MOID_T *candidate = MOID (p);
11187           int k;
11188 /* Depref as far as allowed */
11189           for (k = depref_level; k > 0 && is_deprefable (candidate); k--) {
11190             candidate = depref_once (candidate);
11191           }
11192 /* Only need testing if all allowed deprefs succeeded */
11193           if (k == 0) {
11194             PACK_T *q;
11195             MOID_T *to = (return_depreffed ? depref_completely (candidate) : candidate);
11196             BOOL_T all_coercible = A68_TRUE;
11197             go_on = A68_TRUE;
11198             for (q = PACK (m); q != NO_PACK && all_coercible; FORWARD (q)) {
11199               MOID_T *from = MOID (q);
11200               if (p != q && from != to) {
11201                 all_coercible &= is_coercible (from, to, sort, deflex);
11202               }
11203             }
11204 /* If the pack is coercible to the candidate, we mark the candidate.
11205    We continue searching for longest series of REF REF PROC REF . */
11206             if (all_coercible) {
11207               MOID_T *mark = (return_depreffed ? MOID (p) : candidate);
11208               if (common == NO_MOID) {
11209                 common = mark;
11210               } else if (IS (candidate, FLEX_SYMBOL) && DEFLEX (candidate) == common) {
11211 /* We prefer FLEX */
11212                 common = mark;
11213               }
11214             }
11215           }
11216         }
11217       }                         /* for */
11218     }                           /* for */
11219   }
11220   return (common == NO_MOID ? m : common);
11221 }
11222 
11223 /**
11224 @brief Whether we can search a common mode from a clause or not.
11225 @param att Attribute.
11226 @return See brief description.
11227 **/
11228 
11229 static BOOL_T
clause_allows_balancing(int att)11230 clause_allows_balancing (int att)
11231 {
11232   switch (att) {
11233   case CLOSED_CLAUSE:
11234   case CONDITIONAL_CLAUSE:
11235   case CASE_CLAUSE:
11236   case SERIAL_CLAUSE:
11237   case CONFORMITY_CLAUSE:
11238     {
11239       return (A68_TRUE);
11240     }
11241   }
11242   return (A68_FALSE);
11243 }
11244 
11245 /**
11246 @brief A unique mode from "z".
11247 @param z Soid.
11248 @param deflex Deflexing regime.
11249 @return See brief description.
11250 **/
11251 
11252 static MOID_T *
determine_unique_mode(SOID_T * z,int deflex)11253 determine_unique_mode (SOID_T * z, int deflex)
11254 {
11255   if (z == NO_SOID) {
11256     return (NO_MOID);
11257   } else {
11258     MOID_T *x = MOID (z);
11259     if (is_mode_isnt_well (x)) {
11260       return (MODE (ERROR));
11261     }
11262     x = make_united_mode (x);
11263     if (clause_allows_balancing (ATTRIBUTE (z))) {
11264       return (get_balanced_mode (x, STRONG, NO_DEPREF, deflex));
11265     } else {
11266       return (x);
11267     }
11268   }
11269 }
11270 
11271 /**
11272 @brief Give a warning when a value is silently discarded.
11273 @param p Node in syntax tree.
11274 @param x Soid.
11275 @param y Soid.
11276 @param c Context.
11277 **/
11278 
11279 static void
warn_for_voiding(NODE_T * p,SOID_T * x,SOID_T * y,int c)11280 warn_for_voiding (NODE_T * p, SOID_T * x, SOID_T * y, int c)
11281 {
11282   (void) c;
11283   if (CAST (x) == A68_FALSE) {
11284     if (MOID (x) == MODE (VOID) && MOID (y) != MODE (ERROR) && !(MOID (y) == MODE (VOID) || !is_nonproc (MOID (y)))) {
11285       if (IS (p, FORMULA)) {
11286         diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, p, WARNING_VOIDED, MOID (y));
11287       } else {
11288         diagnostic_node (A68_WARNING, p, WARNING_VOIDED, MOID (y));
11289       }
11290     }
11291   }
11292 }
11293 
11294 /**
11295 @brief Warn for things that are likely unintended.
11296 @param p Node in syntax tree.
11297 @param m Moid.
11298 @param c Context.
11299 @param u Attribute.
11300 **/
11301 
11302 static void
semantic_pitfall(NODE_T * p,MOID_T * m,int c,int u)11303 semantic_pitfall (NODE_T * p, MOID_T * m, int c, int u)
11304 {
11305 /*
11306 semantic_pitfall: warn for things that are likely unintended, for instance
11307                   REF INT i := LOC INT := 0, which should probably be
11308                   REF INT i = LOC INT := 0.
11309 */
11310   if (IS (p, u)) {
11311     diagnostic_node (A68_WARNING, p, WARNING_UNINTENDED, MOID (p), u, m, c);
11312   } else if (is_one_of (p, UNIT, TERTIARY, SECONDARY, PRIMARY, STOP)) {
11313     semantic_pitfall (SUB (p), m, c, u);
11314   }
11315 }
11316 
11317 /**
11318 @brief Insert coercion "a" in the tree.
11319 @param l Node in syntax tree.
11320 @param a Attribute.
11321 @param m (coerced) moid
11322 **/
11323 
11324 static void
make_coercion(NODE_T * l,int a,MOID_T * m)11325 make_coercion (NODE_T * l, int a, MOID_T * m)
11326 {
11327   make_sub (l, l, a);
11328   MOID (l) = depref_rows (MOID (l), m);
11329 }
11330 
11331 /**
11332 @brief Make widening coercion.
11333 @param n Node in syntax tree.
11334 @param p Mode.
11335 @param q Mode.
11336 **/
11337 
11338 static void
make_widening_coercion(NODE_T * n,MOID_T * p,MOID_T * q)11339 make_widening_coercion (NODE_T * n, MOID_T * p, MOID_T * q)
11340 {
11341   MOID_T *z = widens_to (p, q);
11342   make_coercion (n, WIDENING, z);
11343   if (z != q) {
11344     make_widening_coercion (n, z, q);
11345   }
11346 }
11347 
11348 /**
11349 @brief Make ref rowing coercion.
11350 @param n Node in syntax tree.
11351 @param p Mode.
11352 @param q Mode.
11353 **/
11354 
11355 static void
make_ref_rowing_coercion(NODE_T * n,MOID_T * p,MOID_T * q)11356 make_ref_rowing_coercion (NODE_T * n, MOID_T * p, MOID_T * q)
11357 {
11358   if (DEFLEX (p) != DEFLEX (q)) {
11359     if (is_widenable (p, q)) {
11360       make_widening_coercion (n, p, q);
11361     } else if (is_ref_row (q)) {
11362       make_ref_rowing_coercion (n, p, NAME (q));
11363       make_coercion (n, ROWING, q);
11364     }
11365   }
11366 }
11367 
11368 /**
11369 @brief Make rowing coercion.
11370 @param n Node in syntax tree.
11371 @param p Mode.
11372 @param q Mode.
11373 **/
11374 
11375 static void
make_rowing_coercion(NODE_T * n,MOID_T * p,MOID_T * q)11376 make_rowing_coercion (NODE_T * n, MOID_T * p, MOID_T * q)
11377 {
11378   if (DEFLEX (p) != DEFLEX (q)) {
11379     if (is_widenable (p, q)) {
11380       make_widening_coercion (n, p, q);
11381     } else if (SLICE (q) != NO_MOID) {
11382       make_rowing_coercion (n, p, SLICE (q));
11383       make_coercion (n, ROWING, q);
11384     } else if (IS (q, FLEX_SYMBOL)) {
11385       make_rowing_coercion (n, p, SUB (q));
11386     } else if (is_ref_row (q)) {
11387       make_ref_rowing_coercion (n, p, q);
11388     }
11389   }
11390 }
11391 
11392 /**
11393 @brief Make uniting coercion.
11394 @param n Node in syntax tree.
11395 @param q Mode.
11396 **/
11397 
11398 static void
make_uniting_coercion(NODE_T * n,MOID_T * q)11399 make_uniting_coercion (NODE_T * n, MOID_T * q)
11400 {
11401   make_coercion (n, UNITING, derow (q));
11402   if (IS (q, ROW_SYMBOL) || IS (q, FLEX_SYMBOL)) {
11403     make_rowing_coercion (n, derow (q), q);
11404   }
11405 }
11406 
11407 /**
11408 @brief Make depreffing coercion.
11409 @param n Node in syntax tree.
11410 @param p Mode.
11411 @param q Mode.
11412 **/
11413 
11414 static void
make_depreffing_coercion(NODE_T * n,MOID_T * p,MOID_T * q)11415 make_depreffing_coercion (NODE_T * n, MOID_T * p, MOID_T * q)
11416 {
11417   if (DEFLEX (p) == DEFLEX (q)) {
11418     return;
11419   } else if (q == MODE (SIMPLOUT) && is_printable_mode (p)) {
11420     make_coercion (n, UNITING, q);
11421   } else if (q == MODE (ROW_SIMPLOUT) && is_printable_mode (p)) {
11422     make_coercion (n, UNITING, MODE (SIMPLOUT));
11423     make_coercion (n, ROWING, MODE (ROW_SIMPLOUT));
11424   } else if (q == MODE (SIMPLIN) && is_readable_mode (p)) {
11425     make_coercion (n, UNITING, q);
11426   } else if (q == MODE (ROW_SIMPLIN) && is_readable_mode (p)) {
11427     make_coercion (n, UNITING, MODE (SIMPLIN));
11428     make_coercion (n, ROWING, MODE (ROW_SIMPLIN));
11429   } else if (q == MODE (ROWS) && is_rows_type (p)) {
11430     make_coercion (n, UNITING, MODE (ROWS));
11431     MOID (n) = MODE (ROWS);
11432   } else if (is_widenable (p, q)) {
11433     make_widening_coercion (n, p, q);
11434   } else if (is_unitable (p, derow (q), SAFE_DEFLEXING)) {
11435     make_uniting_coercion (n, q);
11436   } else if (is_ref_row (q) && is_strong_name (p, q)) {
11437     make_ref_rowing_coercion (n, p, q);
11438   } else if (SLICE (q) != NO_MOID && is_strong_slice (p, q)) {
11439     make_rowing_coercion (n, p, q);
11440   } else if (IS (q, FLEX_SYMBOL) && is_strong_slice (p, q)) {
11441     make_rowing_coercion (n, p, q);
11442   } else if (IS (p, REF_SYMBOL)) {
11443     MOID_T *r = depref_once (p);
11444     make_coercion (n, DEREFERENCING, r);
11445     make_depreffing_coercion (n, r, q);
11446   } else if (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
11447     MOID_T *r = SUB (p);
11448     make_coercion (n, DEPROCEDURING, r);
11449     make_depreffing_coercion (n, r, q);
11450   } else if (p != q) {
11451     cannot_coerce (n, p, q, NO_SORT, SKIP_DEFLEXING, 0);
11452   }
11453 }
11454 
11455 /**
11456 @brief Whether p is a nonproc mode (that is voided directly).
11457 @param p Mode.
11458 @return See brief description.
11459 **/
11460 
11461 static BOOL_T
is_nonproc(MOID_T * p)11462 is_nonproc (MOID_T * p)
11463 {
11464   if (IS (p, PROC_SYMBOL) && PACK (p) == NO_PACK) {
11465     return (A68_FALSE);
11466   } else if (IS (p, REF_SYMBOL)) {
11467     return (is_nonproc (SUB (p)));
11468   } else {
11469     return (A68_TRUE);
11470   }
11471 }
11472 
11473 /**
11474 @brief Make_void: voiden in an appropriate way.
11475 @param p Node in syntax tree.
11476 @param q Mode.
11477 **/
11478 
11479 static void
make_void(NODE_T * p,MOID_T * q)11480 make_void (NODE_T * p, MOID_T * q)
11481 {
11482   switch (ATTRIBUTE (p)) {
11483   case ASSIGNATION:
11484   case IDENTITY_RELATION:
11485   case GENERATOR:
11486   case CAST:
11487   case DENOTATION:
11488     {
11489       make_coercion (p, VOIDING, MODE (VOID));
11490       return;
11491     }
11492   }
11493 /* MORFs are an involved case */
11494   switch (ATTRIBUTE (p)) {
11495   case SELECTION:
11496   case SLICE:
11497   case ROUTINE_TEXT:
11498   case FORMULA:
11499   case CALL:
11500   case IDENTIFIER:
11501     {
11502 /* A nonproc moid value is eliminated directly */
11503       if (is_nonproc (q)) {
11504         make_coercion (p, VOIDING, MODE (VOID));
11505         return;
11506       } else {
11507 /* Descend the chain of e.g. REF PROC .. until a nonproc moid remains */
11508         MOID_T *z = q;
11509         while (!is_nonproc (z)) {
11510           if (IS (z, REF_SYMBOL)) {
11511             make_coercion (p, DEREFERENCING, SUB (z));
11512           }
11513           if (IS (z, PROC_SYMBOL) && NODE_PACK (p) == NO_PACK) {
11514             make_coercion (p, DEPROCEDURING, SUB (z));
11515           }
11516           z = SUB (z);
11517         }
11518         if (z != MODE (VOID)) {
11519           make_coercion (p, VOIDING, MODE (VOID));
11520         }
11521         return;
11522       }
11523     }
11524   }
11525 /* All other is voided straight away */
11526   make_coercion (p, VOIDING, MODE (VOID));
11527 }
11528 
11529 /**
11530 @brief Make strong coercion.
11531 @param n Node in syntax tree.
11532 @param p Mode.
11533 @param q Mode.
11534 **/
11535 
11536 static void
make_strong(NODE_T * n,MOID_T * p,MOID_T * q)11537 make_strong (NODE_T * n, MOID_T * p, MOID_T * q)
11538 {
11539   if (q == MODE (VOID) && p != MODE (VOID)) {
11540     make_void (n, p);
11541   } else {
11542     make_depreffing_coercion (n, p, q);
11543   }
11544 }
11545 
11546 /**
11547 @brief Mode check on bounds.
11548 @param p Node in syntax tree.
11549 **/
11550 
11551 static void
mode_check_bounds(NODE_T * p)11552 mode_check_bounds (NODE_T * p)
11553 {
11554   if (p == NO_NODE) {
11555     return;
11556   } else if (IS (p, UNIT)) {
11557     SOID_T x, y;
11558     make_soid (&x, STRONG, MODE (INT), 0);
11559     mode_check_unit (p, &x, &y);
11560     if (!is_coercible_in_context (&y, &x, SAFE_DEFLEXING)) {
11561       cannot_coerce (p, MOID (&y), MODE (INT), MEEK, SAFE_DEFLEXING, UNIT);
11562     }
11563     mode_check_bounds (NEXT (p));
11564   } else {
11565     mode_check_bounds (SUB (p));
11566     mode_check_bounds (NEXT (p));
11567   }
11568 }
11569 
11570 /**
11571 @brief Mode check declarer.
11572 @param p Node in syntax tree.
11573 **/
11574 
11575 static void
mode_check_declarer(NODE_T * p)11576 mode_check_declarer (NODE_T * p)
11577 {
11578   if (p == NO_NODE) {
11579     return;
11580   } else if (IS (p, BOUNDS)) {
11581     mode_check_bounds (SUB (p));
11582     mode_check_declarer (NEXT (p));
11583   } else {
11584     mode_check_declarer (SUB (p));
11585     mode_check_declarer (NEXT (p));
11586   }
11587 }
11588 
11589 /**
11590 @brief Mode check identity declaration.
11591 @param p Node in syntax tree.
11592 **/
11593 
11594 static void
mode_check_identity_declaration(NODE_T * p)11595 mode_check_identity_declaration (NODE_T * p)
11596 {
11597   if (p != NO_NODE) {
11598     switch (ATTRIBUTE (p)) {
11599     case DECLARER:
11600       {
11601         mode_check_declarer (SUB (p));
11602         mode_check_identity_declaration (NEXT (p));
11603         break;
11604       }
11605     case DEFINING_IDENTIFIER:
11606       {
11607         SOID_T x, y;
11608         make_soid (&x, STRONG, MOID (p), 0);
11609         mode_check_unit (NEXT_NEXT (p), &x, &y);
11610         if (!is_coercible_in_context (&y, &x, SAFE_DEFLEXING)) {
11611           cannot_coerce (NEXT_NEXT (p), MOID (&y), MOID (&x), STRONG, SAFE_DEFLEXING, UNIT);
11612         } else if (MOID (&x) != MOID (&y)) {
11613 /* Check for instance, REF INT i = LOC REF INT */
11614           semantic_pitfall (NEXT_NEXT (p), MOID (&x), IDENTITY_DECLARATION, GENERATOR);
11615         }
11616         break;
11617       }
11618     default:
11619       {
11620         mode_check_identity_declaration (SUB (p));
11621         mode_check_identity_declaration (NEXT (p));
11622         break;
11623       }
11624     }
11625   }
11626 }
11627 
11628 /**
11629 @brief Mode check variable declaration.
11630 @param p Node in syntax tree.
11631 **/
11632 
11633 static void
mode_check_variable_declaration(NODE_T * p)11634 mode_check_variable_declaration (NODE_T * p)
11635 {
11636   if (p != NO_NODE) {
11637     switch (ATTRIBUTE (p)) {
11638     case DECLARER:
11639       {
11640         mode_check_declarer (SUB (p));
11641         mode_check_variable_declaration (NEXT (p));
11642         break;
11643       }
11644     case DEFINING_IDENTIFIER:
11645       {
11646         if (whether (p, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, UNIT, STOP)) {
11647           SOID_T x, y;
11648           make_soid (&x, STRONG, SUB_MOID (p), 0);
11649           mode_check_unit (NEXT_NEXT (p), &x, &y);
11650           if (!is_coercible_in_context (&y, &x, FORCE_DEFLEXING)) {
11651             cannot_coerce (p, MOID (&y), MOID (&x), STRONG, FORCE_DEFLEXING, UNIT);
11652           } else if (SUB_MOID (&x) != MOID (&y)) {
11653 /* Check for instance, REF INT i = LOC REF INT */
11654             semantic_pitfall (NEXT_NEXT (p), MOID (&x), VARIABLE_DECLARATION, GENERATOR);
11655           }
11656         }
11657         break;
11658       }
11659     default:
11660       {
11661         mode_check_variable_declaration (SUB (p));
11662         mode_check_variable_declaration (NEXT (p));
11663         break;
11664       }
11665     }
11666   }
11667 }
11668 
11669 /**
11670 @brief Mode check routine text.
11671 @param p Node in syntax tree.
11672 @param y Resulting soid.
11673 **/
11674 
11675 static void
mode_check_routine_text(NODE_T * p,SOID_T * y)11676 mode_check_routine_text (NODE_T * p, SOID_T * y)
11677 {
11678   SOID_T w;
11679   if (IS (p, PARAMETER_PACK)) {
11680     mode_check_declarer (SUB (p));
11681     FORWARD (p);
11682   }
11683   mode_check_declarer (SUB (p));
11684   make_soid (&w, STRONG, MOID (p), 0);
11685   mode_check_unit (NEXT_NEXT (p), &w, y);
11686   if (!is_coercible_in_context (y, &w, FORCE_DEFLEXING)) {
11687     cannot_coerce (NEXT_NEXT (p), MOID (y), MOID (&w), STRONG, FORCE_DEFLEXING, UNIT);
11688   }
11689 }
11690 
11691 /**
11692 @brief Mode check proc declaration.
11693 @param p Node in syntax tree.
11694 **/
11695 
11696 static void
mode_check_proc_declaration(NODE_T * p)11697 mode_check_proc_declaration (NODE_T * p)
11698 {
11699   if (p == NO_NODE) {
11700     return;
11701   } else if (IS (p, ROUTINE_TEXT)) {
11702     SOID_T x, y;
11703     make_soid (&x, STRONG, NO_MOID, 0);
11704     mode_check_routine_text (SUB (p), &y);
11705   } else {
11706     mode_check_proc_declaration (SUB (p));
11707     mode_check_proc_declaration (NEXT (p));
11708   }
11709 }
11710 
11711 /**
11712 @brief Mode check brief op declaration.
11713 @param p Node in syntax tree.
11714 **/
11715 
11716 static void
mode_check_brief_op_declaration(NODE_T * p)11717 mode_check_brief_op_declaration (NODE_T * p)
11718 {
11719   if (p == NO_NODE) {
11720     return;
11721   } else if (IS (p, DEFINING_OPERATOR)) {
11722     SOID_T y;
11723     if (MOID (p) != MOID (NEXT_NEXT (p))) {
11724       SOID_T y2, x;
11725       make_soid (&y2, NO_SORT, MOID (NEXT_NEXT (p)), 0);
11726       make_soid (&x, NO_SORT, MOID (p), 0);
11727       cannot_coerce (NEXT_NEXT (p), MOID (&y2), MOID (&x), STRONG, SKIP_DEFLEXING, ROUTINE_TEXT);
11728     }
11729     mode_check_routine_text (SUB (NEXT_NEXT (p)), &y);
11730   } else {
11731     mode_check_brief_op_declaration (SUB (p));
11732     mode_check_brief_op_declaration (NEXT (p));
11733   }
11734 }
11735 
11736 /**
11737 @brief Mode check op declaration.
11738 @param p Node in syntax tree.
11739 **/
11740 
11741 static void
mode_check_op_declaration(NODE_T * p)11742 mode_check_op_declaration (NODE_T * p)
11743 {
11744   if (p == NO_NODE) {
11745     return;
11746   } else if (IS (p, DEFINING_OPERATOR)) {
11747     SOID_T y, x;
11748     make_soid (&x, STRONG, MOID (p), 0);
11749     mode_check_unit (NEXT_NEXT (p), &x, &y);
11750     if (!is_coercible_in_context (&y, &x, SAFE_DEFLEXING)) {
11751       cannot_coerce (NEXT_NEXT (p), MOID (&y), MOID (&x), STRONG, SAFE_DEFLEXING, UNIT);
11752     }
11753   } else {
11754     mode_check_op_declaration (SUB (p));
11755     mode_check_op_declaration (NEXT (p));
11756   }
11757 }
11758 
11759 /**
11760 @brief Mode check declaration list.
11761 @param p Node in syntax tree.
11762 **/
11763 
11764 static void
mode_check_declaration_list(NODE_T * p)11765 mode_check_declaration_list (NODE_T * p)
11766 {
11767   if (p != NO_NODE) {
11768     switch (ATTRIBUTE (p)) {
11769     case IDENTITY_DECLARATION:
11770       {
11771         mode_check_identity_declaration (SUB (p));
11772         break;
11773       }
11774     case VARIABLE_DECLARATION:
11775       {
11776         mode_check_variable_declaration (SUB (p));
11777         break;
11778       }
11779     case MODE_DECLARATION:
11780       {
11781         mode_check_declarer (SUB (p));
11782         break;
11783       }
11784     case PROCEDURE_DECLARATION:
11785     case PROCEDURE_VARIABLE_DECLARATION:
11786       {
11787         mode_check_proc_declaration (SUB (p));
11788         break;
11789       }
11790     case BRIEF_OPERATOR_DECLARATION:
11791       {
11792         mode_check_brief_op_declaration (SUB (p));
11793         break;
11794       }
11795     case OPERATOR_DECLARATION:
11796       {
11797         mode_check_op_declaration (SUB (p));
11798         break;
11799       }
11800     default:
11801       {
11802         mode_check_declaration_list (SUB (p));
11803         mode_check_declaration_list (NEXT (p));
11804         break;
11805       }
11806     }
11807   }
11808 }
11809 
11810 /**
11811 @brief Mode check serial clause.
11812 @param r Resulting soids.
11813 @param p Node in syntax tree.
11814 @param x Expected soid.
11815 @param k Whether statement yields a value other than VOID.
11816 **/
11817 
11818 static void
mode_check_serial(SOID_T ** r,NODE_T * p,SOID_T * x,BOOL_T k)11819 mode_check_serial (SOID_T ** r, NODE_T * p, SOID_T * x, BOOL_T k)
11820 {
11821   if (p == NO_NODE) {
11822     return;
11823   } else if (IS (p, INITIALISER_SERIES)) {
11824     mode_check_serial (r, SUB (p), x, A68_FALSE);
11825     mode_check_serial (r, NEXT (p), x, k);
11826   } else if (IS (p, DECLARATION_LIST)) {
11827     mode_check_declaration_list (SUB (p));
11828   } else if (is_one_of (p, LABEL, SEMI_SYMBOL, EXIT_SYMBOL, STOP)) {
11829     mode_check_serial (r, NEXT (p), x, k);
11830   } else if (is_one_of (p, SERIAL_CLAUSE, ENQUIRY_CLAUSE, STOP)) {
11831     if (NEXT (p) != NO_NODE) {
11832       if (IS (NEXT (p), EXIT_SYMBOL) || IS (NEXT (p), END_SYMBOL) || IS (NEXT (p), CLOSE_SYMBOL)) {
11833         mode_check_serial (r, SUB (p), x, A68_TRUE);
11834       } else {
11835         mode_check_serial (r, SUB (p), x, A68_FALSE);
11836       }
11837       mode_check_serial (r, NEXT (p), x, k);
11838     } else {
11839       mode_check_serial (r, SUB (p), x, A68_TRUE);
11840     }
11841   } else if (IS (p, LABELED_UNIT)) {
11842     mode_check_serial (r, SUB (p), x, k);
11843   } else if (IS (p, UNIT)) {
11844     SOID_T y;
11845     if (k) {
11846       mode_check_unit (p, x, &y);
11847     } else {
11848       SOID_T w;
11849       make_soid (&w, STRONG, MODE (VOID), 0);
11850       mode_check_unit (p, &w, &y);
11851     }
11852     if (NEXT (p) != NO_NODE) {
11853       mode_check_serial (r, NEXT (p), x, k);
11854     } else {
11855       if (k) {
11856         add_to_soid_list (r, p, &y);
11857       }
11858     }
11859   }
11860 }
11861 
11862 /**
11863 @brief Mode check serial clause units.
11864 @param p Node in syntax tree.
11865 @param x Expected soid.
11866 @param y Resulting soid.
11867 @param att Attribute (SERIAL or ENQUIRY).
11868 **/
11869 
11870 static void
mode_check_serial_units(NODE_T * p,SOID_T * x,SOID_T * y,int att)11871 mode_check_serial_units (NODE_T * p, SOID_T * x, SOID_T * y, int att)
11872 {
11873   SOID_T *top_sl = NO_SOID;
11874   (void) att;
11875   mode_check_serial (&top_sl, SUB (p), x, A68_TRUE);
11876   if (is_balanced (p, top_sl, SORT (x))) {
11877     MOID_T *result = pack_soids_in_moid (top_sl, SERIES_MODE);
11878     make_soid (y, SORT (x), result, SERIAL_CLAUSE);
11879   } else {
11880     make_soid (y, SORT (x), (MOID (x) != NO_MOID ? MOID (x) : MODE (ERROR)), 0);
11881   }
11882   free_soid_list (top_sl);
11883 }
11884 
11885 /**
11886 @brief Mode check unit list.
11887 @param r Resulting soids.
11888 @param p Node in syntax tree.
11889 @param x Expected soid.
11890 **/
11891 
11892 static void
mode_check_unit_list(SOID_T ** r,NODE_T * p,SOID_T * x)11893 mode_check_unit_list (SOID_T ** r, NODE_T * p, SOID_T * x)
11894 {
11895   if (p == NO_NODE) {
11896     return;
11897   } else if (IS (p, UNIT_LIST)) {
11898     mode_check_unit_list (r, SUB (p), x);
11899     mode_check_unit_list (r, NEXT (p), x);
11900   } else if (IS (p, COMMA_SYMBOL)) {
11901     mode_check_unit_list (r, NEXT (p), x);
11902   } else if (IS (p, UNIT)) {
11903     SOID_T y;
11904     mode_check_unit (p, x, &y);
11905     add_to_soid_list (r, p, &y);
11906     mode_check_unit_list (r, NEXT (p), x);
11907   }
11908 }
11909 
11910 /**
11911 @brief Mode check struct display.
11912 @param r Resulting soids.
11913 @param p Node in syntax tree.
11914 @param fields Pack.
11915 **/
11916 
11917 static void
mode_check_struct_display(SOID_T ** r,NODE_T * p,PACK_T ** fields)11918 mode_check_struct_display (SOID_T ** r, NODE_T * p, PACK_T ** fields)
11919 {
11920   if (p == NO_NODE) {
11921     return;
11922   } else if (IS (p, UNIT_LIST)) {
11923     mode_check_struct_display (r, SUB (p), fields);
11924     mode_check_struct_display (r, NEXT (p), fields);
11925   } else if (IS (p, COMMA_SYMBOL)) {
11926     mode_check_struct_display (r, NEXT (p), fields);
11927   } else if (IS (p, UNIT)) {
11928     SOID_T x, y;
11929     if (*fields != NO_PACK) {
11930       make_soid (&x, STRONG, MOID (*fields), 0);
11931       FORWARD (*fields);
11932     } else {
11933       make_soid (&x, STRONG, NO_MOID, 0);
11934     }
11935     mode_check_unit (p, &x, &y);
11936     add_to_soid_list (r, p, &y);
11937     mode_check_struct_display (r, NEXT (p), fields);
11938   }
11939 }
11940 
11941 /**
11942 @brief Mode check get specified moids.
11943 @param p Node in syntax tree.
11944 @param u United mode to add to.
11945 **/
11946 
11947 static void
mode_check_get_specified_moids(NODE_T * p,MOID_T * u)11948 mode_check_get_specified_moids (NODE_T * p, MOID_T * u)
11949 {
11950   for (; p != NO_NODE; FORWARD (p)) {
11951     if (is_one_of (p, SPECIFIED_UNIT_LIST, SPECIFIED_UNIT, STOP)) {
11952       mode_check_get_specified_moids (SUB (p), u);
11953     } else if (IS (p, SPECIFIER)) {
11954       MOID_T *m = MOID (NEXT_SUB (p));
11955       add_mode_to_pack (&(PACK (u)), m, NO_TEXT, NODE (m));
11956     }
11957   }
11958 }
11959 
11960 /**
11961 @brief Mode check specified unit list.
11962 @param r Resulting soids.
11963 @param p Node in syntax tree.
11964 @param x Expected soid.
11965 @param u Resulting united mode.
11966 **/
11967 
11968 static void
mode_check_specified_unit_list(SOID_T ** r,NODE_T * p,SOID_T * x,MOID_T * u)11969 mode_check_specified_unit_list (SOID_T ** r, NODE_T * p, SOID_T * x, MOID_T * u)
11970 {
11971   for (; p != NO_NODE; FORWARD (p)) {
11972     if (is_one_of (p, SPECIFIED_UNIT_LIST, SPECIFIED_UNIT, STOP)) {
11973       mode_check_specified_unit_list (r, SUB (p), x, u);
11974     } else if (IS (p, SPECIFIER)) {
11975       MOID_T *m = MOID (NEXT_SUB (p));
11976       if (u != NO_MOID && !is_unitable (m, u, SAFE_DEFLEXING)) {
11977         diagnostic_node (A68_ERROR, p, ERROR_NO_COMPONENT, m, u);
11978       }
11979     } else if (IS (p, UNIT)) {
11980       SOID_T y;
11981       mode_check_unit (p, x, &y);
11982       add_to_soid_list (r, p, &y);
11983     }
11984   }
11985 }
11986 
11987 /**
11988 @brief Mode check united case parts.
11989 @param ry Resulting soids.
11990 @param p Node in syntax tree.
11991 @param x Expected soid.
11992 **/
11993 
11994 static void
mode_check_united_case_parts(SOID_T ** ry,NODE_T * p,SOID_T * x)11995 mode_check_united_case_parts (SOID_T ** ry, NODE_T * p, SOID_T * x)
11996 {
11997   SOID_T enq_expct, enq_yield;
11998   MOID_T *u = NO_MOID, *v = NO_MOID, *w = NO_MOID;
11999 /* Check the CASE part and deduce the united mode */
12000   make_soid (&enq_expct, STRONG, NO_MOID, 0);
12001   mode_check_serial_units (NEXT_SUB (p), &enq_expct, &enq_yield, ENQUIRY_CLAUSE);
12002 /* Deduce the united mode from the enquiry clause */
12003   u = depref_completely (MOID (&enq_yield));
12004   u = make_united_mode (u);
12005   u = depref_completely (u);
12006 /* Also deduce the united mode from the specifiers */
12007   v = new_moid ();
12008   ATTRIBUTE (v) = SERIES_MODE;
12009   mode_check_get_specified_moids (NEXT_SUB (NEXT (p)), v);
12010   v = make_united_mode (v);
12011 /* Determine a resulting union */
12012   if (u == MODE (HIP)) {
12013     w = v;
12014   } else {
12015     if (IS (u, UNION_SYMBOL)) {
12016       BOOL_T uv, vu, some;
12017       investigate_firm_relations (PACK (u), PACK (v), &uv, &some);
12018       investigate_firm_relations (PACK (v), PACK (u), &vu, &some);
12019       if (uv && vu) {
12020 /* Every component has a specifier */
12021         w = u;
12022       } else if (!uv && !vu) {
12023 /* Hmmmm ... let the coercer sort it out */
12024         w = u;
12025       } else {
12026 /*  This is all the balancing we allow here for the moment. Firmly related
12027 subsets are not valid so we absorb them. If this doesn't solve it then we
12028 get a coercion-error later */
12029         w = absorb_related_subsets (u);
12030       }
12031     } else {
12032       diagnostic_node (A68_ERROR, NEXT_SUB (p), ERROR_NO_UNION, u);
12033       return;
12034     }
12035   }
12036   MOID (SUB (p)) = w;
12037   FORWARD (p);
12038 /* Check the IN part */
12039   mode_check_specified_unit_list (ry, NEXT_SUB (p), x, w);
12040 /* OUSE, OUT, ESAC */
12041   if ((FORWARD (p)) != NO_NODE) {
12042     if (is_one_of (p, OUT_PART, CHOICE, STOP)) {
12043       mode_check_serial (ry, NEXT_SUB (p), x, A68_TRUE);
12044     } else if (is_one_of (p, CONFORMITY_OUSE_PART, BRIEF_CONFORMITY_OUSE_PART, STOP)) {
12045       mode_check_united_case_parts (ry, SUB (p), x);
12046     }
12047   }
12048 }
12049 
12050 /**
12051 @brief Mode check united case.
12052 @param p Node in syntax tree.
12053 @param x Expected soid.
12054 @param y Resulting soid.
12055 **/
12056 
12057 static void
mode_check_united_case(NODE_T * p,SOID_T * x,SOID_T * y)12058 mode_check_united_case (NODE_T * p, SOID_T * x, SOID_T * y)
12059 {
12060   SOID_T *top_sl = NO_SOID;
12061   MOID_T *z;
12062   mode_check_united_case_parts (&top_sl, p, x);
12063   if (!is_balanced (p, top_sl, SORT (x))) {
12064     if (MOID (x) != NO_MOID) {
12065       make_soid (y, SORT (x), MOID (x), CONFORMITY_CLAUSE);
12066 
12067     } else {
12068       make_soid (y, SORT (x), MODE (ERROR), 0);
12069     }
12070   } else {
12071     z = pack_soids_in_moid (top_sl, SERIES_MODE);
12072     make_soid (y, SORT (x), z, CONFORMITY_CLAUSE);
12073   }
12074   free_soid_list (top_sl);
12075 }
12076 
12077 /**
12078 @brief Mode check unit list 2.
12079 @param p Node in syntax tree.
12080 @param x Expected soid.
12081 @param y Resulting soid.
12082 **/
12083 
12084 static void
mode_check_unit_list_2(NODE_T * p,SOID_T * x,SOID_T * y)12085 mode_check_unit_list_2 (NODE_T * p, SOID_T * x, SOID_T * y)
12086 {
12087   SOID_T *top_sl = NO_SOID;
12088   if (MOID (x) != NO_MOID) {
12089     if (IS (MOID (x), FLEX_SYMBOL)) {
12090       SOID_T y2;
12091       make_soid (&y2, SORT (x), SLICE (SUB_MOID (x)), 0);
12092       mode_check_unit_list (&top_sl, SUB (p), &y2);
12093     } else if (IS (MOID (x), ROW_SYMBOL)) {
12094       SOID_T y2;
12095       make_soid (&y2, SORT (x), SLICE (MOID (x)), 0);
12096       mode_check_unit_list (&top_sl, SUB (p), &y2);
12097     } else if (IS (MOID (x), STRUCT_SYMBOL)) {
12098       PACK_T *y2 = PACK (MOID (x));
12099       mode_check_struct_display (&top_sl, SUB (p), &y2);
12100     } else {
12101       mode_check_unit_list (&top_sl, SUB (p), x);
12102     }
12103   } else {
12104     mode_check_unit_list (&top_sl, SUB (p), x);
12105   }
12106   make_soid (y, STRONG, pack_soids_in_moid (top_sl, STOWED_MODE), 0);
12107   free_soid_list (top_sl);
12108 }
12109 
12110 /**
12111 @brief Mode check closed.
12112 @param p Node in syntax tree.
12113 @param x Expected soid.
12114 @param y Resulting soid.
12115 **/
12116 
12117 static void
mode_check_closed(NODE_T * p,SOID_T * x,SOID_T * y)12118 mode_check_closed (NODE_T * p, SOID_T * x, SOID_T * y)
12119 {
12120   if (p == NO_NODE) {
12121     return;
12122   } else if (IS (p, SERIAL_CLAUSE)) {
12123     mode_check_serial_units (p, x, y, SERIAL_CLAUSE);
12124   } else if (is_one_of (p, OPEN_SYMBOL, BEGIN_SYMBOL, STOP)) {
12125     mode_check_closed (NEXT (p), x, y);
12126   }
12127   MOID (p) = MOID (y);
12128 }
12129 
12130 /**
12131 @brief Mode check collateral.
12132 @param p Node in syntax tree.
12133 @param x Expected soid.
12134 @param y Resulting soid.
12135 **/
12136 
12137 static void
mode_check_collateral(NODE_T * p,SOID_T * x,SOID_T * y)12138 mode_check_collateral (NODE_T * p, SOID_T * x, SOID_T * y)
12139 {
12140   if (p == NO_NODE) {
12141     return;
12142   } else if (whether (p, BEGIN_SYMBOL, END_SYMBOL, STOP)
12143              || whether (p, OPEN_SYMBOL, CLOSE_SYMBOL, STOP)) {
12144     if (SORT (x) == STRONG) {
12145       if (MOID (x) == NO_MOID) {
12146         diagnostic_node (A68_ERROR, p, ERROR_VACUO, "REF MODE");
12147       } else {
12148         MOID_T *z = (IS (MOID (x), FLEX_SYMBOL) ? SUB_MOID (x) : MOID (x));
12149         make_soid (y, STRONG, MODE (VACUUM), 0);
12150         if (SUB (z) != NO_MOID && HAS_ROWS (SUB (z))) {
12151           diagnostic_node (A68_ERROR, p, ERROR_VACUUM, "REF", MOID (x));
12152         }
12153       }
12154     } else {
12155       make_soid (y, STRONG, MODE (UNDEFINED), 0);
12156     }
12157   } else {
12158     if (IS (p, UNIT_LIST)) {
12159       mode_check_unit_list_2 (p, x, y);
12160     } else if (is_one_of (p, OPEN_SYMBOL, BEGIN_SYMBOL, STOP)) {
12161       mode_check_collateral (NEXT (p), x, y);
12162     }
12163     MOID (p) = MOID (y);
12164   }
12165 }
12166 
12167 /**
12168 @brief Mode check conditional 2.
12169 @param ry Resulting soids.
12170 @param p Node in syntax tree.
12171 @param x Expected soid.
12172 **/
12173 
12174 static void
mode_check_conditional_2(SOID_T ** ry,NODE_T * p,SOID_T * x)12175 mode_check_conditional_2 (SOID_T ** ry, NODE_T * p, SOID_T * x)
12176 {
12177   SOID_T enq_expct, enq_yield;
12178   make_soid (&enq_expct, STRONG, MODE (BOOL), 0);
12179   mode_check_serial_units (NEXT_SUB (p), &enq_expct, &enq_yield, ENQUIRY_CLAUSE);
12180   if (!is_coercible_in_context (&enq_yield, &enq_expct, SAFE_DEFLEXING)) {
12181     cannot_coerce (p, MOID (&enq_yield), MOID (&enq_expct), MEEK, SAFE_DEFLEXING, ENQUIRY_CLAUSE);
12182   }
12183   FORWARD (p);
12184   mode_check_serial (ry, NEXT_SUB (p), x, A68_TRUE);
12185   if ((FORWARD (p)) != NO_NODE) {
12186     if (is_one_of (p, ELSE_PART, CHOICE, STOP)) {
12187       mode_check_serial (ry, NEXT_SUB (p), x, A68_TRUE);
12188     } else if (is_one_of (p, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
12189       mode_check_conditional_2 (ry, SUB (p), x);
12190     }
12191   }
12192 }
12193 
12194 /**
12195 @brief Mode check conditional.
12196 @param p Node in syntax tree.
12197 @param x Expected soid.
12198 @param y Resulting soid.
12199 **/
12200 
12201 static void
mode_check_conditional(NODE_T * p,SOID_T * x,SOID_T * y)12202 mode_check_conditional (NODE_T * p, SOID_T * x, SOID_T * y)
12203 {
12204   SOID_T *top_sl = NO_SOID;
12205   MOID_T *z;
12206   mode_check_conditional_2 (&top_sl, p, x);
12207   if (!is_balanced (p, top_sl, SORT (x))) {
12208     if (MOID (x) != NO_MOID) {
12209       make_soid (y, SORT (x), MOID (x), CONDITIONAL_CLAUSE);
12210     } else {
12211       make_soid (y, SORT (x), MODE (ERROR), 0);
12212     }
12213   } else {
12214     z = pack_soids_in_moid (top_sl, SERIES_MODE);
12215     make_soid (y, SORT (x), z, CONDITIONAL_CLAUSE);
12216   }
12217   free_soid_list (top_sl);
12218 }
12219 
12220 /**
12221 @brief Mode check int case 2.
12222 @param ry Resulting soids.
12223 @param p Node in syntax tree.
12224 @param x Expected soid.
12225 **/
12226 
12227 static void
mode_check_int_case_2(SOID_T ** ry,NODE_T * p,SOID_T * x)12228 mode_check_int_case_2 (SOID_T ** ry, NODE_T * p, SOID_T * x)
12229 {
12230   SOID_T enq_expct, enq_yield;
12231   make_soid (&enq_expct, STRONG, MODE (INT), 0);
12232   mode_check_serial_units (NEXT_SUB (p), &enq_expct, &enq_yield, ENQUIRY_CLAUSE);
12233   if (!is_coercible_in_context (&enq_yield, &enq_expct, SAFE_DEFLEXING)) {
12234     cannot_coerce (p, MOID (&enq_yield), MOID (&enq_expct), MEEK, SAFE_DEFLEXING, ENQUIRY_CLAUSE);
12235   }
12236   FORWARD (p);
12237   mode_check_unit_list (ry, NEXT_SUB (p), x);
12238   if ((FORWARD (p)) != NO_NODE) {
12239     if (is_one_of (p, OUT_PART, CHOICE, STOP)) {
12240       mode_check_serial (ry, NEXT_SUB (p), x, A68_TRUE);
12241     } else if (is_one_of (p, CASE_OUSE_PART, BRIEF_OUSE_PART, STOP)) {
12242       mode_check_int_case_2 (ry, SUB (p), x);
12243     }
12244   }
12245 }
12246 
12247 /**
12248 @brief Mode check int case.
12249 @param p Node in syntax tree.
12250 @param x Expected soid.
12251 @param y Resulting soid.
12252 **/
12253 
12254 static void
mode_check_int_case(NODE_T * p,SOID_T * x,SOID_T * y)12255 mode_check_int_case (NODE_T * p, SOID_T * x, SOID_T * y)
12256 {
12257   SOID_T *top_sl = NO_SOID;
12258   MOID_T *z;
12259   mode_check_int_case_2 (&top_sl, p, x);
12260   if (!is_balanced (p, top_sl, SORT (x))) {
12261     if (MOID (x) != NO_MOID) {
12262       make_soid (y, SORT (x), MOID (x), CASE_CLAUSE);
12263     } else {
12264       make_soid (y, SORT (x), MODE (ERROR), 0);
12265     }
12266   } else {
12267     z = pack_soids_in_moid (top_sl, SERIES_MODE);
12268     make_soid (y, SORT (x), z, CASE_CLAUSE);
12269   }
12270   free_soid_list (top_sl);
12271 }
12272 
12273 /**
12274 @brief Mode check loop 2.
12275 @param p Node in syntax tree.
12276 @param y Resulting soid.
12277 **/
12278 
12279 static void
mode_check_loop_2(NODE_T * p,SOID_T * y)12280 mode_check_loop_2 (NODE_T * p, SOID_T * y)
12281 {
12282   if (p == NO_NODE) {
12283     return;
12284   } else if (IS (p, FOR_PART)) {
12285     mode_check_loop_2 (NEXT (p), y);
12286   } else if (is_one_of (p, FROM_PART, BY_PART, TO_PART, STOP)) {
12287     SOID_T ix, iy;
12288     make_soid (&ix, STRONG, MODE (INT), 0);
12289     mode_check_unit (NEXT_SUB (p), &ix, &iy);
12290     if (!is_coercible_in_context (&iy, &ix, SAFE_DEFLEXING)) {
12291       cannot_coerce (NEXT_SUB (p), MOID (&iy), MODE (INT), MEEK, SAFE_DEFLEXING, ENQUIRY_CLAUSE);
12292     }
12293     mode_check_loop_2 (NEXT (p), y);
12294   } else if (IS (p, WHILE_PART)) {
12295     SOID_T enq_expct, enq_yield;
12296     make_soid (&enq_expct, STRONG, MODE (BOOL), 0);
12297     mode_check_serial_units (NEXT_SUB (p), &enq_expct, &enq_yield, ENQUIRY_CLAUSE);
12298     if (!is_coercible_in_context (&enq_yield, &enq_expct, SAFE_DEFLEXING)) {
12299       cannot_coerce (p, MOID (&enq_yield), MOID (&enq_expct), MEEK, SAFE_DEFLEXING, ENQUIRY_CLAUSE);
12300     }
12301     mode_check_loop_2 (NEXT (p), y);
12302   } else if (is_one_of (p, DO_PART, ALT_DO_PART, STOP)) {
12303     SOID_T *z = NO_SOID;
12304     SOID_T ix;
12305     NODE_T *do_p = NEXT_SUB (p), *un_p;
12306     make_soid (&ix, STRONG, MODE (VOID), 0);
12307     if (IS (do_p, SERIAL_CLAUSE)) {
12308       mode_check_serial (&z, do_p, &ix, A68_TRUE);
12309       un_p = NEXT (do_p);
12310     } else {
12311       un_p = do_p;
12312     }
12313     if (un_p != NO_NODE && IS (un_p, UNTIL_PART)) {
12314       SOID_T enq_expct, enq_yield;
12315       make_soid (&enq_expct, STRONG, MODE (BOOL), 0);
12316       mode_check_serial_units (NEXT_SUB (un_p), &enq_expct, &enq_yield, ENQUIRY_CLAUSE);
12317       if (!is_coercible_in_context (&enq_yield, &enq_expct, SAFE_DEFLEXING)) {
12318         cannot_coerce (un_p, MOID (&enq_yield), MOID (&enq_expct), MEEK, SAFE_DEFLEXING, ENQUIRY_CLAUSE);
12319       }
12320     }
12321     free_soid_list (z);
12322   }
12323 }
12324 
12325 /**
12326 @brief Mode check loop.
12327 @param p Node in syntax tree.
12328 @param y Resulting soid.
12329 **/
12330 
12331 static void
mode_check_loop(NODE_T * p,SOID_T * y)12332 mode_check_loop (NODE_T * p, SOID_T * y)
12333 {
12334   SOID_T *z = NO_SOID;
12335   mode_check_loop_2 (p, /* y */ z);
12336   make_soid (y, STRONG, MODE (VOID), 0);
12337 }
12338 
12339 /**
12340 @brief Mode check enclosed.
12341 @param p Node in syntax tree.
12342 @param x Expected soid.
12343 @param y Resulting soid.
12344 **/
12345 
12346 void
mode_check_enclosed(NODE_T * p,SOID_T * x,SOID_T * y)12347 mode_check_enclosed (NODE_T * p, SOID_T * x, SOID_T * y)
12348 {
12349   if (p == NO_NODE) {
12350     return;
12351   } else if (IS (p, ENCLOSED_CLAUSE)) {
12352     mode_check_enclosed (SUB (p), x, y);
12353   } else if (IS (p, CLOSED_CLAUSE)) {
12354     mode_check_closed (SUB (p), x, y);
12355   } else if (IS (p, PARALLEL_CLAUSE)) {
12356     mode_check_collateral (SUB (NEXT_SUB (p)), x, y);
12357     make_soid (y, STRONG, MODE (VOID), 0);
12358     MOID (NEXT_SUB (p)) = MODE (VOID);
12359   } else if (IS (p, COLLATERAL_CLAUSE)) {
12360     mode_check_collateral (SUB (p), x, y);
12361   } else if (IS (p, CONDITIONAL_CLAUSE)) {
12362     mode_check_conditional (SUB (p), x, y);
12363   } else if (IS (p, CASE_CLAUSE)) {
12364     mode_check_int_case (SUB (p), x, y);
12365   } else if (IS (p, CONFORMITY_CLAUSE)) {
12366     mode_check_united_case (SUB (p), x, y);
12367   } else if (IS (p, LOOP_CLAUSE)) {
12368     mode_check_loop (SUB (p), y);
12369   }
12370   MOID (p) = MOID (y);
12371 }
12372 
12373 /**
12374 @brief Search table for operator.
12375 @param t Tag chain to search.
12376 @param n Name of operator.
12377 @param x Lhs mode.
12378 @param y Rhs mode.
12379 @return Tag entry.
12380 **/
12381 
12382 static TAG_T *
search_table_for_operator(TAG_T * t,char * n,MOID_T * x,MOID_T * y)12383 search_table_for_operator (TAG_T * t, char *n, MOID_T * x, MOID_T * y)
12384 {
12385   if (is_mode_isnt_well (x)) {
12386     return (error_tag);
12387   } else if (y != NO_MOID && is_mode_isnt_well (y)) {
12388     return (error_tag);
12389   }
12390   for (; t != NO_TAG; FORWARD (t)) {
12391     if (NSYMBOL (NODE (t)) == n) {
12392       PACK_T *p = PACK (MOID (t));
12393       if (is_coercible (x, MOID (p), FIRM, ALIAS_DEFLEXING)) {
12394         FORWARD (p);
12395         if (p == NO_PACK && y == NO_MOID) {
12396 /* Matched in case of a monadic */
12397           return (t);
12398         } else if (p != NO_PACK && y != NO_MOID && is_coercible (y, MOID (p), FIRM, ALIAS_DEFLEXING)) {
12399 /* Matched in case of a dyadic */
12400           return (t);
12401         }
12402       }
12403     }
12404   }
12405   return (NO_TAG);
12406 }
12407 
12408 /**
12409 @brief Search chain of symbol tables and return matching operator "x n y" or "n x".
12410 @param s Symbol table to start search.
12411 @param n Name of token.
12412 @param x Lhs mode.
12413 @param y Rhs mode.
12414 @return Tag entry.
12415 **/
12416 
12417 static TAG_T *
search_table_chain_for_operator(TABLE_T * s,char * n,MOID_T * x,MOID_T * y)12418 search_table_chain_for_operator (TABLE_T * s, char *n, MOID_T * x, MOID_T * y)
12419 {
12420   if (is_mode_isnt_well (x)) {
12421     return (error_tag);
12422   } else if (y != NO_MOID && is_mode_isnt_well (y)) {
12423     return (error_tag);
12424   }
12425   while (s != NO_TABLE) {
12426     TAG_T *z = search_table_for_operator (OPERATORS (s), n, x, y);
12427     if (z != NO_TAG) {
12428       return (z);
12429     }
12430     BACKWARD (s);
12431   }
12432   return (NO_TAG);
12433 }
12434 
12435 /**
12436 @brief Return a matching operator "x n y".
12437 @param s Symbol table to start search.
12438 @param n Name of token.
12439 @param x Lhs mode.
12440 @param y Rhs mode.
12441 @return Tag entry.
12442 **/
12443 
12444 static TAG_T *
find_operator(TABLE_T * s,char * n,MOID_T * x,MOID_T * y)12445 find_operator (TABLE_T * s, char *n, MOID_T * x, MOID_T * y)
12446 {
12447 /* Coercions to operand modes are FIRM */
12448   TAG_T *z;
12449   MOID_T *u, *v;
12450 /* (A) Catch exceptions first */
12451   if (x == NO_MOID && y == NO_MOID) {
12452     return (NO_TAG);
12453   } else if (is_mode_isnt_well (x)) {
12454     return (error_tag);
12455   } else if (y != NO_MOID && is_mode_isnt_well (y)) {
12456     return (error_tag);
12457   }
12458 /* (B) MONADs */
12459   if (x != NO_MOID && y == NO_MOID) {
12460     z = search_table_chain_for_operator (s, n, x, NO_MOID);
12461     if (z != NO_TAG) {
12462       return (z);
12463     } else {
12464 /* (B.2) A little trick to allow - (0, 1) or ABS (1, long pi) */
12465       if (is_coercible (x, MODE (COMPLEX), STRONG, SAFE_DEFLEXING)) {
12466         z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (COMPLEX), NO_MOID);
12467         if (z != NO_TAG) {
12468           return (z);
12469         }
12470       }
12471       if (is_coercible (x, MODE (LONG_COMPLEX), STRONG, SAFE_DEFLEXING)) {
12472         z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (LONG_COMPLEX), NO_MOID);
12473         if (z != NO_TAG) {
12474           return (z);
12475         }
12476       }
12477       if (is_coercible (x, MODE (LONGLONG_COMPLEX), STRONG, SAFE_DEFLEXING)) {
12478         z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (LONGLONG_COMPLEX), NO_MOID);
12479       }
12480     }
12481     return (NO_TAG);
12482   }
12483 /* (C) DYADs */
12484   z = search_table_chain_for_operator (s, n, x, y);
12485   if (z != NO_TAG) {
12486     return (z);
12487   }
12488 /* (C.2) Vector and matrix "strong coercions" in standard environ */
12489   u = depref_completely (x);
12490   v = depref_completely (y);
12491   if ((u == MODE (ROW_REAL) || u == MODE (ROWROW_REAL))
12492       || (v == MODE (ROW_REAL) || v == MODE (ROWROW_REAL))
12493       || (u == MODE (ROW_COMPLEX) || u == MODE (ROWROW_COMPLEX))
12494       || (v == MODE (ROW_COMPLEX) || v == MODE (ROWROW_COMPLEX))) {
12495     if (u == MODE (INT)) {
12496       z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (REAL), y);
12497       if (z != NO_TAG) {
12498         return (z);
12499       }
12500       z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (COMPLEX), y);
12501       if (z != NO_TAG) {
12502         return (z);
12503       }
12504     } else if (v == MODE (INT)) {
12505       z = search_table_for_operator (OPERATORS (a68g_standenv), n, x, MODE (REAL));
12506       if (z != NO_TAG) {
12507         return (z);
12508       }
12509       z = search_table_for_operator (OPERATORS (a68g_standenv), n, x, MODE (COMPLEX));
12510       if (z != NO_TAG) {
12511         return (z);
12512       }
12513     } else if (u == MODE (REAL)) {
12514       z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (COMPLEX), y);
12515       if (z != NO_TAG) {
12516         return (z);
12517       }
12518     } else if (v == MODE (REAL)) {
12519       z = search_table_for_operator (OPERATORS (a68g_standenv), n, x, MODE (COMPLEX));
12520       if (z != NO_TAG) {
12521         return (z);
12522       }
12523     }
12524   }
12525 /* (C.3) Look in standenv for an appropriate cross-term */
12526   u = make_series_from_moids (x, y);
12527   u = make_united_mode (u);
12528   v = get_balanced_mode (u, STRONG, NO_DEPREF, SAFE_DEFLEXING);
12529   z = search_table_for_operator (OPERATORS (a68g_standenv), n, v, v);
12530   if (z != NO_TAG) {
12531     return (z);
12532   }
12533   if (is_coercible_series (u, MODE (REAL), STRONG, SAFE_DEFLEXING)) {
12534     z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (REAL), MODE (REAL));
12535     if (z != NO_TAG) {
12536       return (z);
12537     }
12538   }
12539   if (is_coercible_series (u, MODE (LONG_REAL), STRONG, SAFE_DEFLEXING)) {
12540     z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (LONG_REAL), MODE (LONG_REAL));
12541     if (z != NO_TAG) {
12542       return (z);
12543     }
12544   }
12545   if (is_coercible_series (u, MODE (LONGLONG_REAL), STRONG, SAFE_DEFLEXING)) {
12546     z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (LONGLONG_REAL), MODE (LONGLONG_REAL));
12547     if (z != NO_TAG) {
12548       return (z);
12549     }
12550   }
12551   if (is_coercible_series (u, MODE (COMPLEX), STRONG, SAFE_DEFLEXING)) {
12552     z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (COMPLEX), MODE (COMPLEX));
12553     if (z != NO_TAG) {
12554       return (z);
12555     }
12556   }
12557   if (is_coercible_series (u, MODE (LONG_COMPLEX), STRONG, SAFE_DEFLEXING)) {
12558     z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (LONG_COMPLEX), MODE (LONG_COMPLEX));
12559     if (z != NO_TAG) {
12560       return (z);
12561     }
12562   }
12563   if (is_coercible_series (u, MODE (LONGLONG_COMPLEX), STRONG, SAFE_DEFLEXING)) {
12564     z = search_table_for_operator (OPERATORS (a68g_standenv), n, MODE (LONGLONG_COMPLEX), MODE (LONGLONG_COMPLEX));
12565     if (z != NO_TAG) {
12566       return (z);
12567     }
12568   }
12569 /* (C.4) Now allow for depreffing for REF REAL +:= INT and alike */
12570   v = get_balanced_mode (u, STRONG, DEPREF, SAFE_DEFLEXING);
12571   z = search_table_for_operator (OPERATORS (a68g_standenv), n, v, v);
12572   if (z != NO_TAG) {
12573     return (z);
12574   }
12575   return (NO_TAG);
12576 }
12577 
12578 /**
12579 @brief Mode check monadic operator.
12580 @param p Node in syntax tree.
12581 @param x Expected soid.
12582 @param y Resulting soid.
12583 **/
12584 
12585 static void
mode_check_monadic_operator(NODE_T * p,SOID_T * x,SOID_T * y)12586 mode_check_monadic_operator (NODE_T * p, SOID_T * x, SOID_T * y)
12587 {
12588   if (p != NO_NODE) {
12589     TAG_T *t;
12590     MOID_T *u;
12591     u = determine_unique_mode (y, SAFE_DEFLEXING);
12592     if (is_mode_isnt_well (u)) {
12593       make_soid (y, SORT (x), MODE (ERROR), 0);
12594     } else if (u == MODE (HIP)) {
12595       diagnostic_node (A68_ERROR, NEXT (p), ERROR_INVALID_OPERAND, u);
12596       make_soid (y, SORT (x), MODE (ERROR), 0);
12597     } else {
12598       if (a68g_strchr (NOMADS, *(NSYMBOL (p))) != NO_TEXT) {
12599         t = NO_TAG;
12600         diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_OPERATOR_INVALID, NOMADS);
12601         make_soid (y, SORT (x), MODE (ERROR), 0);
12602       } else {
12603         t = find_operator (TABLE (p), NSYMBOL (p), u, NO_MOID);
12604         if (t == NO_TAG) {
12605           diagnostic_node (A68_ERROR, p, ERROR_NO_MONADIC, u);
12606           make_soid (y, SORT (x), MODE (ERROR), 0);
12607         }
12608       }
12609       if (t != NO_TAG) {
12610         MOID (p) = MOID (t);
12611       }
12612       TAX (p) = t;
12613       if (t != NO_TAG && t != error_tag) {
12614         MOID (p) = MOID (t);
12615         make_soid (y, SORT (x), SUB_MOID (t), 0);
12616       } else {
12617         MOID (p) = MODE (ERROR);
12618         make_soid (y, SORT (x), MODE (ERROR), 0);
12619       }
12620     }
12621   }
12622 }
12623 
12624 /**
12625 @brief Mode check monadic formula.
12626 @param p Node in syntax tree.
12627 @param x Expected soid.
12628 @param y Resulting soid.
12629 **/
12630 
12631 static void
mode_check_monadic_formula(NODE_T * p,SOID_T * x,SOID_T * y)12632 mode_check_monadic_formula (NODE_T * p, SOID_T * x, SOID_T * y)
12633 {
12634   SOID_T e;
12635   make_soid (&e, FIRM, NO_MOID, 0);
12636   mode_check_formula (NEXT (p), &e, y);
12637   mode_check_monadic_operator (p, &e, y);
12638   make_soid (y, SORT (x), MOID (y), 0);
12639 }
12640 
12641 /**
12642 @brief Mode check formula.
12643 @param p Node in syntax tree.
12644 @param x Expected soid.
12645 @param y Resulting soid.
12646 **/
12647 
12648 static void
mode_check_formula(NODE_T * p,SOID_T * x,SOID_T * y)12649 mode_check_formula (NODE_T * p, SOID_T * x, SOID_T * y)
12650 {
12651   SOID_T ls, rs;
12652   TAG_T *op;
12653   MOID_T *u, *v;
12654   if (IS (p, MONADIC_FORMULA)) {
12655     mode_check_monadic_formula (SUB (p), x, &ls);
12656   } else if (IS (p, FORMULA)) {
12657     mode_check_formula (SUB (p), x, &ls);
12658   } else if (IS (p, SECONDARY)) {
12659     SOID_T e;
12660     make_soid (&e, FIRM, NO_MOID, 0);
12661     mode_check_unit (SUB (p), &e, &ls);
12662   }
12663   u = determine_unique_mode (&ls, SAFE_DEFLEXING);
12664   MOID (p) = u;
12665   if (NEXT (p) == NO_NODE) {
12666     make_soid (y, SORT (x), u, 0);
12667   } else {
12668     NODE_T *q = NEXT_NEXT (p);
12669     if (IS (q, MONADIC_FORMULA)) {
12670       mode_check_monadic_formula (SUB (NEXT_NEXT (p)), x, &rs);
12671     } else if (IS (q, FORMULA)) {
12672       mode_check_formula (SUB (NEXT_NEXT (p)), x, &rs);
12673     } else if (IS (q, SECONDARY)) {
12674       SOID_T e;
12675       make_soid (&e, FIRM, NO_MOID, 0);
12676       mode_check_unit (SUB (q), &e, &rs);
12677     }
12678     v = determine_unique_mode (&rs, SAFE_DEFLEXING);
12679     MOID (q) = v;
12680     if (is_mode_isnt_well (u) || is_mode_isnt_well (v)) {
12681       make_soid (y, SORT (x), MODE (ERROR), 0);
12682     } else if (u == MODE (HIP)) {
12683       diagnostic_node (A68_ERROR, p, ERROR_INVALID_OPERAND, u);
12684       make_soid (y, SORT (x), MODE (ERROR), 0);
12685     } else if (v == MODE (HIP)) {
12686       diagnostic_node (A68_ERROR, q, ERROR_INVALID_OPERAND, u);
12687       make_soid (y, SORT (x), MODE (ERROR), 0);
12688     } else {
12689       op = find_operator (TABLE (NEXT (p)), NSYMBOL (NEXT (p)), u, v);
12690       if (op == NO_TAG) {
12691         diagnostic_node (A68_ERROR, NEXT (p), ERROR_NO_DYADIC, u, v);
12692         make_soid (y, SORT (x), MODE (ERROR), 0);
12693       }
12694       if (op != NO_TAG) {
12695         MOID (NEXT (p)) = MOID (op);
12696       }
12697       TAX (NEXT (p)) = op;
12698       if (op != NO_TAG && op != error_tag) {
12699         make_soid (y, SORT (x), SUB_MOID (op), 0);
12700       } else {
12701         make_soid (y, SORT (x), MODE (ERROR), 0);
12702       }
12703     }
12704   }
12705 }
12706 
12707 /**
12708 @brief Mode check assignation.
12709 @param p Node in syntax tree.
12710 @param x Expected soid.
12711 @param y Resulting soid.
12712 **/
12713 
12714 static void
mode_check_assignation(NODE_T * p,SOID_T * x,SOID_T * y)12715 mode_check_assignation (NODE_T * p, SOID_T * x, SOID_T * y)
12716 {
12717   SOID_T name, tmp, value;
12718   MOID_T *name_moid, *ori;
12719 /* Get destination mode */
12720   make_soid (&name, SOFT, NO_MOID, 0);
12721   mode_check_unit (SUB (p), &name, &tmp);
12722 /* SOFT coercion */
12723   ori = determine_unique_mode (&tmp, SAFE_DEFLEXING);
12724   name_moid = deproc_completely (ori);
12725   if (ATTRIBUTE (name_moid) != REF_SYMBOL) {
12726     if (IF_MODE_IS_WELL (name_moid)) {
12727       diagnostic_node (A68_ERROR, p, ERROR_NO_NAME, ori, ATTRIBUTE (SUB (p)));
12728     }
12729     make_soid (y, SORT (x), MODE (ERROR), 0);
12730     return;
12731   }
12732   MOID (p) = name_moid;
12733 /* Get source mode */
12734   make_soid (&name, STRONG, SUB (name_moid), 0);
12735   mode_check_unit (NEXT_NEXT (p), &name, &value);
12736   if (!is_coercible_in_context (&value, &name, FORCE_DEFLEXING)) {
12737     cannot_coerce (p, MOID (&value), MOID (&name), STRONG, FORCE_DEFLEXING, UNIT);
12738     make_soid (y, SORT (x), MODE (ERROR), 0);
12739   } else {
12740     make_soid (y, SORT (x), name_moid, 0);
12741   }
12742 }
12743 
12744 /**
12745 @brief Mode check identity relation.
12746 @param p Node in syntax tree.
12747 @param x Expected soid.
12748 @param y Resulting soid.
12749 **/
12750 
12751 static void
mode_check_identity_relation(NODE_T * p,SOID_T * x,SOID_T * y)12752 mode_check_identity_relation (NODE_T * p, SOID_T * x, SOID_T * y)
12753 {
12754   SOID_T e, l, r;
12755   MOID_T *lhs, *rhs, *oril, *orir;
12756   NODE_T *ln = p, *rn = NEXT_NEXT (p);
12757   make_soid (&e, SOFT, NO_MOID, 0);
12758   mode_check_unit (SUB (ln), &e, &l);
12759   mode_check_unit (SUB (rn), &e, &r);
12760 /* SOFT coercion */
12761   oril = determine_unique_mode (&l, SAFE_DEFLEXING);
12762   orir = determine_unique_mode (&r, SAFE_DEFLEXING);
12763   lhs = deproc_completely (oril);
12764   rhs = deproc_completely (orir);
12765   if (IF_MODE_IS_WELL (lhs) && lhs != MODE (HIP) && ATTRIBUTE (lhs) != REF_SYMBOL) {
12766     diagnostic_node (A68_ERROR, ln, ERROR_NO_NAME, oril, ATTRIBUTE (SUB (ln)));
12767     lhs = MODE (ERROR);
12768   }
12769   if (IF_MODE_IS_WELL (rhs) && rhs != MODE (HIP) && ATTRIBUTE (rhs) != REF_SYMBOL) {
12770     diagnostic_node (A68_ERROR, rn, ERROR_NO_NAME, orir, ATTRIBUTE (SUB (rn)));
12771     rhs = MODE (ERROR);
12772   }
12773   if (lhs == MODE (HIP) && rhs == MODE (HIP)) {
12774     diagnostic_node (A68_ERROR, p, ERROR_NO_UNIQUE_MODE);
12775   }
12776   if (is_coercible (lhs, rhs, STRONG, SAFE_DEFLEXING)) {
12777     lhs = rhs;
12778   } else if (is_coercible (rhs, lhs, STRONG, SAFE_DEFLEXING)) {
12779     rhs = lhs;
12780   } else {
12781     cannot_coerce (NEXT (p), rhs, lhs, SOFT, SKIP_DEFLEXING, TERTIARY);
12782     lhs = rhs = MODE (ERROR);
12783   }
12784   MOID (ln) = lhs;
12785   MOID (rn) = rhs;
12786   make_soid (y, SORT (x), MODE (BOOL), 0);
12787 }
12788 
12789 /**
12790 @brief Mode check bool functions ANDF and ORF.
12791 @param p Node in syntax tree.
12792 @param x Expected soid.
12793 @param y Resulting soid.
12794 **/
12795 
12796 static void
mode_check_bool_function(NODE_T * p,SOID_T * x,SOID_T * y)12797 mode_check_bool_function (NODE_T * p, SOID_T * x, SOID_T * y)
12798 {
12799   SOID_T e, l, r;
12800   NODE_T *ln = p, *rn = NEXT_NEXT (p);
12801   make_soid (&e, STRONG, MODE (BOOL), 0);
12802   mode_check_unit (SUB (ln), &e, &l);
12803   if (!is_coercible_in_context (&l, &e, SAFE_DEFLEXING)) {
12804     cannot_coerce (ln, MOID (&l), MOID (&e), MEEK, SAFE_DEFLEXING, TERTIARY);
12805   }
12806   mode_check_unit (SUB (rn), &e, &r);
12807   if (!is_coercible_in_context (&r, &e, SAFE_DEFLEXING)) {
12808     cannot_coerce (rn, MOID (&r), MOID (&e), MEEK, SAFE_DEFLEXING, TERTIARY);
12809   }
12810   MOID (ln) = MODE (BOOL);
12811   MOID (rn) = MODE (BOOL);
12812   make_soid (y, SORT (x), MODE (BOOL), 0);
12813 }
12814 
12815 /**
12816 @brief Mode check cast.
12817 @param p Node in syntax tree.
12818 @param x Expected soid.
12819 @param y Resulting soid.
12820 **/
12821 
12822 static void
mode_check_cast(NODE_T * p,SOID_T * x,SOID_T * y)12823 mode_check_cast (NODE_T * p, SOID_T * x, SOID_T * y)
12824 {
12825   SOID_T w;
12826   mode_check_declarer (p);
12827   make_soid (&w, STRONG, MOID (p), 0);
12828   CAST (&w) = A68_TRUE;
12829   mode_check_enclosed (SUB_NEXT (p), &w, y);
12830   if (!is_coercible_in_context (y, &w, SAFE_DEFLEXING)) {
12831     cannot_coerce (NEXT (p), MOID (y), MOID (&w), STRONG, SAFE_DEFLEXING, ENCLOSED_CLAUSE);
12832   }
12833   make_soid (y, SORT (x), MOID (p), 0);
12834 }
12835 
12836 /**
12837 @brief Mode check assertion.
12838 @param p Node in syntax tree.
12839 **/
12840 
12841 static void
mode_check_assertion(NODE_T * p)12842 mode_check_assertion (NODE_T * p)
12843 {
12844   SOID_T w, y;
12845   make_soid (&w, STRONG, MODE (BOOL), 0);
12846   mode_check_enclosed (SUB_NEXT (p), &w, &y);
12847   SORT (&y) = SORT (&w);        /* Patch */
12848   if (!is_coercible_in_context (&y, &w, NO_DEFLEXING)) {
12849     cannot_coerce (NEXT (p), MOID (&y), MOID (&w), MEEK, NO_DEFLEXING, ENCLOSED_CLAUSE);
12850   }
12851 }
12852 
12853 /**
12854 @brief Mode check argument list.
12855 @param r Resulting soids.
12856 @param p Node in syntax tree.
12857 @param x Proc argument pack.
12858 @param v Partial locale pack.
12859 @param w Partial proc pack.
12860 **/
12861 
12862 static void
mode_check_argument_list(SOID_T ** r,NODE_T * p,PACK_T ** x,PACK_T ** v,PACK_T ** w)12863 mode_check_argument_list (SOID_T ** r, NODE_T * p, PACK_T ** x, PACK_T ** v, PACK_T ** w)
12864 {
12865   for (; p != NO_NODE; FORWARD (p)) {
12866     if (IS (p, GENERIC_ARGUMENT_LIST)) {
12867       ATTRIBUTE (p) = ARGUMENT_LIST;
12868     }
12869     if (IS (p, ARGUMENT_LIST)) {
12870       mode_check_argument_list (r, SUB (p), x, v, w);
12871     } else if (IS (p, UNIT)) {
12872       SOID_T y, z;
12873       if (*x != NO_PACK) {
12874         make_soid (&z, STRONG, MOID (*x), 0);
12875         add_mode_to_pack_end (v, MOID (*x), NO_TEXT, p);
12876         FORWARD (*x);
12877       } else {
12878         make_soid (&z, STRONG, NO_MOID, 0);
12879       }
12880       mode_check_unit (p, &z, &y);
12881       add_to_soid_list (r, p, &y);
12882     } else if (IS (p, TRIMMER)) {
12883       SOID_T z;
12884       if (SUB (p) != NO_NODE) {
12885         diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_SYNTAX, ARGUMENT);
12886         make_soid (&z, STRONG, MODE (ERROR), 0);
12887         add_mode_to_pack_end (v, MODE (VOID), NO_TEXT, p);
12888         add_mode_to_pack_end (w, MOID (*x), NO_TEXT, p);
12889         FORWARD (*x);
12890       } else if (*x != NO_PACK) {
12891         make_soid (&z, STRONG, MOID (*x), 0);
12892         add_mode_to_pack_end (v, MODE (VOID), NO_TEXT, p);
12893         add_mode_to_pack_end (w, MOID (*x), NO_TEXT, p);
12894         FORWARD (*x);
12895       } else {
12896         make_soid (&z, STRONG, NO_MOID, 0);
12897       }
12898       add_to_soid_list (r, p, &z);
12899     } else if (IS (p, SUB_SYMBOL) && !OPTION_BRACKETS (&program)) {
12900       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_SYNTAX, CALL);
12901     }
12902   }
12903 }
12904 
12905 /**
12906 @brief Mode check argument list 2.
12907 @param p Node in syntax tree.
12908 @param x Proc argument pack.
12909 @param y Soid.
12910 @param v Partial locale pack.
12911 @param w Partial proc pack.
12912 **/
12913 
12914 static void
mode_check_argument_list_2(NODE_T * p,PACK_T * x,SOID_T * y,PACK_T ** v,PACK_T ** w)12915 mode_check_argument_list_2 (NODE_T * p, PACK_T * x, SOID_T * y, PACK_T ** v, PACK_T ** w)
12916 {
12917   SOID_T *top_sl = NO_SOID;
12918   mode_check_argument_list (&top_sl, SUB (p), &x, v, w);
12919   make_soid (y, STRONG, pack_soids_in_moid (top_sl, STOWED_MODE), 0);
12920   free_soid_list (top_sl);
12921 }
12922 
12923 /**
12924 @brief Mode check meek int.
12925 @param p Node in syntax tree.
12926 **/
12927 
12928 static void
mode_check_meek_int(NODE_T * p)12929 mode_check_meek_int (NODE_T * p)
12930 {
12931   SOID_T x, y;
12932   make_soid (&x, STRONG, MODE (INT), 0);
12933   mode_check_unit (p, &x, &y);
12934   if (!is_coercible_in_context (&y, &x, SAFE_DEFLEXING)) {
12935     cannot_coerce (p, MOID (&y), MOID (&x), MEEK, SAFE_DEFLEXING, 0);
12936   }
12937 }
12938 
12939 /**
12940 @brief Mode check trimmer.
12941 @param p Node in syntax tree.
12942 **/
12943 
12944 static void
mode_check_trimmer(NODE_T * p)12945 mode_check_trimmer (NODE_T * p)
12946 {
12947   if (p == NO_NODE) {
12948     return;
12949   } else if (IS (p, TRIMMER)) {
12950     mode_check_trimmer (SUB (p));
12951   } else if (IS (p, UNIT)) {
12952     mode_check_meek_int (p);
12953     mode_check_trimmer (NEXT (p));
12954   } else {
12955     mode_check_trimmer (NEXT (p));
12956   }
12957 }
12958 
12959 /**
12960 @brief Mode check indexer.
12961 @param p Node in syntax tree.
12962 @param subs Subscript counter.
12963 @param trims Trimmer counter.
12964 **/
12965 
12966 static void
mode_check_indexer(NODE_T * p,int * subs,int * trims)12967 mode_check_indexer (NODE_T * p, int *subs, int *trims)
12968 {
12969   if (p == NO_NODE) {
12970     return;
12971   } else if (IS (p, TRIMMER)) {
12972     (*trims)++;
12973     mode_check_trimmer (SUB (p));
12974   } else if (IS (p, UNIT)) {
12975     (*subs)++;
12976     mode_check_meek_int (p);
12977   } else {
12978     mode_check_indexer (SUB (p), subs, trims);
12979     mode_check_indexer (NEXT (p), subs, trims);
12980   }
12981 }
12982 
12983 /**
12984 @brief Mode check call.
12985 @param p Node in syntax tree.
12986 @param n Mode.
12987 @param x Expected soid.
12988 @param y Resulting soid.
12989 **/
12990 
12991 static void
mode_check_call(NODE_T * p,MOID_T * n,SOID_T * x,SOID_T * y)12992 mode_check_call (NODE_T * p, MOID_T * n, SOID_T * x, SOID_T * y)
12993 {
12994   SOID_T d;
12995   MOID (p) = n;
12996 /* "partial_locale" is the mode of the locale */
12997   PARTIAL_LOCALE (GINFO (p)) = new_moid ();
12998   ATTRIBUTE (PARTIAL_LOCALE (GINFO (p))) = PROC_SYMBOL;
12999   PACK (PARTIAL_LOCALE (GINFO (p))) = NO_PACK;
13000   SUB (PARTIAL_LOCALE (GINFO (p))) = SUB (n);
13001 /* "partial_proc" is the mode of the resulting proc */
13002   PARTIAL_PROC (GINFO (p)) = new_moid ();
13003   ATTRIBUTE (PARTIAL_PROC (GINFO (p))) = PROC_SYMBOL;
13004   PACK (PARTIAL_PROC (GINFO (p))) = NO_PACK;
13005   SUB (PARTIAL_PROC (GINFO (p))) = SUB (n);
13006 /* Check arguments and construct modes */
13007   mode_check_argument_list_2 (NEXT (p), PACK (n), &d, &PACK (PARTIAL_LOCALE (GINFO (p))), &PACK (PARTIAL_PROC (GINFO (p))));
13008   DIM (PARTIAL_PROC (GINFO (p))) = count_pack_members (PACK (PARTIAL_PROC (GINFO (p))));
13009   DIM (PARTIAL_LOCALE (GINFO (p))) = count_pack_members (PACK (PARTIAL_LOCALE (GINFO (p))));
13010   PARTIAL_PROC (GINFO (p)) = register_extra_mode (&TOP_MOID (&program), PARTIAL_PROC (GINFO (p)));
13011   PARTIAL_LOCALE (GINFO (p)) = register_extra_mode (&TOP_MOID (&program), PARTIAL_LOCALE (GINFO (p)));
13012   if (DIM (MOID (&d)) != DIM (n)) {
13013     diagnostic_node (A68_ERROR, p, ERROR_ARGUMENT_NUMBER, n);
13014     make_soid (y, SORT (x), SUB (n), 0);
13015 /*  make_soid (y, SORT (x), MODE (ERROR), 0); */
13016   } else {
13017     if (!is_coercible (MOID (&d), n, STRONG, ALIAS_DEFLEXING)) {
13018       cannot_coerce (p, MOID (&d), n, STRONG, ALIAS_DEFLEXING, ARGUMENT);
13019     }
13020     if (DIM (PARTIAL_PROC (GINFO (p))) == 0) {
13021       make_soid (y, SORT (x), SUB (n), 0);
13022     } else {
13023       if (OPTION_PORTCHECK (&program)) {
13024         diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, NEXT (p), WARNING_EXTENSION);
13025       }
13026       make_soid (y, SORT (x), PARTIAL_PROC (GINFO (p)), 0);
13027     }
13028   }
13029 }
13030 
13031 /**
13032 @brief Mode check slice.
13033 @param p Node in syntax tree.
13034 @param ori Original MODE.
13035 @param x Expected soid.
13036 @param y Resulting soid.
13037 @return Whether construct is a CALL or a SLICE.
13038 **/
13039 
13040 static void
mode_check_slice(NODE_T * p,MOID_T * ori,SOID_T * x,SOID_T * y)13041 mode_check_slice (NODE_T * p, MOID_T * ori, SOID_T * x, SOID_T * y)
13042 {
13043   BOOL_T is_ref;
13044   int rowdim, subs, trims;
13045   MOID_T *m = depref_completely (ori), *n = ori;
13046 /* WEAK coercion */
13047   while ((IS (n, REF_SYMBOL) && !is_ref_row (n)) || (IS (n, PROC_SYMBOL) && PACK (n) == NO_PACK)) {
13048     n = depref_once (n);
13049   }
13050   if (n == NO_MOID || !(SLICE (DEFLEX (n)) != NO_MOID || is_ref_row (n))) {
13051     if (IF_MODE_IS_WELL (n)) {
13052       diagnostic_node (A68_ERROR, p, ERROR_NO_ROW_OR_PROC, n, ATTRIBUTE (SUB (p)));
13053     }
13054     make_soid (y, SORT (x), MODE (ERROR), 0);
13055   }
13056 
13057   MOID (p) = n;
13058   subs = trims = 0;
13059   mode_check_indexer (SUB_NEXT (p), &subs, &trims);
13060   if ((is_ref = is_ref_row (n)) != 0) {
13061     rowdim = DIM (DEFLEX (SUB (n)));
13062   } else {
13063     rowdim = DIM (DEFLEX (n));
13064   }
13065   if ((subs + trims) != rowdim) {
13066     diagnostic_node (A68_ERROR, p, ERROR_INDEXER_NUMBER, n);
13067     make_soid (y, SORT (x), MODE (ERROR), 0);
13068   } else {
13069     if (subs > 0 && trims == 0) {
13070       ANNOTATION (NEXT (p)) = SLICE;
13071       m = n;
13072     } else {
13073       ANNOTATION (NEXT (p)) = TRIMMER;
13074       m = n;
13075     }
13076     while (subs > 0) {
13077       if (is_ref) {
13078         m = NAME (m);
13079       } else {
13080         if (IS (m, FLEX_SYMBOL)) {
13081           m = SUB (m);
13082         }
13083         m = SLICE (m);
13084       }
13085       ABEND (m == NO_MOID, "No mode in mode_check_slice", NO_TEXT);
13086       subs--;
13087     }
13088 /* A trim cannot be but deflexed */
13089     if (ANNOTATION (NEXT (p)) == TRIMMER && TRIM (m) != NO_MOID) {
13090       ABEND (TRIM (m) == NO_MOID, ERROR_INTERNAL_CONSISTENCY, NO_TEXT);
13091       make_soid (y, SORT (x), TRIM (m), 0);
13092     } else {
13093       make_soid (y, SORT (x), m, 0);
13094     }
13095   }
13096 }
13097 
13098 /**
13099 @brief Mode check specification.
13100 @param p Node in syntax tree.
13101 @param x Expected soid.
13102 @param y Resulting soid.
13103 @return Whether construct is a CALL or SLICE.
13104 **/
13105 
13106 static int
mode_check_specification(NODE_T * p,SOID_T * x,SOID_T * y)13107 mode_check_specification (NODE_T * p, SOID_T * x, SOID_T * y)
13108 {
13109   SOID_T w, d;
13110   MOID_T *m, *ori;
13111   make_soid (&w, WEAK, NO_MOID, 0);
13112   mode_check_unit (SUB (p), &w, &d);
13113   ori = determine_unique_mode (&d, SAFE_DEFLEXING);
13114   m = depref_completely (ori);
13115   if (IS (m, PROC_SYMBOL)) {
13116 /* Assume CALL */
13117     mode_check_call (p, m, x, y);
13118     return (CALL);
13119   } else if (IS (m, ROW_SYMBOL) || IS (m, FLEX_SYMBOL)) {
13120 /* Assume SLICE */
13121     mode_check_slice (p, ori, x, y);
13122     return (SLICE);
13123   } else {
13124     if (m != MODE (ERROR)) {
13125       diagnostic_node (A68_SYNTAX_ERROR, p, ERROR_MODE_SPECIFICATION, m);
13126     }
13127     make_soid (y, SORT (x), MODE (ERROR), 0);
13128     return (PRIMARY);
13129   }
13130 }
13131 
13132 /**
13133 @brief Mode check selection.
13134 @param p Node in syntax tree.
13135 @param x Expected soid.
13136 @param y Resulting soid.
13137 **/
13138 
13139 static void
mode_check_selection(NODE_T * p,SOID_T * x,SOID_T * y)13140 mode_check_selection (NODE_T * p, SOID_T * x, SOID_T * y)
13141 {
13142   SOID_T w, d;
13143   BOOL_T coerce;
13144   MOID_T *n, *str, *ori;
13145   PACK_T *t, *t_2;
13146   char *fs;
13147   BOOL_T deflex = A68_FALSE;
13148   NODE_T *secondary = SUB_NEXT (p);
13149   make_soid (&w, WEAK, NO_MOID, 0);
13150   mode_check_unit (secondary, &w, &d);
13151   n = ori = determine_unique_mode (&d, SAFE_DEFLEXING);
13152   coerce = A68_TRUE;
13153   while (coerce) {
13154     if (IS (n, STRUCT_SYMBOL)) {
13155       coerce = A68_FALSE;
13156       t = PACK (n);
13157     } else if (IS (n, REF_SYMBOL) && (IS (SUB (n), ROW_SYMBOL) || IS (SUB (n), FLEX_SYMBOL)) && MULTIPLE (n) != NO_MOID) {
13158       coerce = A68_FALSE;
13159       deflex = A68_TRUE;
13160       t = PACK (MULTIPLE (n));
13161     } else if ((IS (n, ROW_SYMBOL) || IS (n, FLEX_SYMBOL)) && MULTIPLE (n) != NO_MOID) {
13162       coerce = A68_FALSE;
13163       deflex = A68_TRUE;
13164       t = PACK (MULTIPLE (n));
13165     } else if (IS (n, REF_SYMBOL) && is_name_struct (n)) {
13166       coerce = A68_FALSE;
13167       t = PACK (NAME (n));
13168     } else if (is_deprefable (n)) {
13169       coerce = A68_TRUE;
13170       n = SUB (n);
13171       t = NO_PACK;
13172     } else {
13173       coerce = A68_FALSE;
13174       t = NO_PACK;
13175     }
13176   }
13177   if (t == NO_PACK) {
13178     if (IF_MODE_IS_WELL (MOID (&d))) {
13179       diagnostic_node (A68_ERROR, secondary, ERROR_NO_STRUCT, ori, ATTRIBUTE (secondary));
13180     }
13181     make_soid (y, SORT (x), MODE (ERROR), 0);
13182     return;
13183   }
13184   MOID (NEXT (p)) = n;
13185   fs = NSYMBOL (SUB (p));
13186   str = n;
13187   while (IS (str, REF_SYMBOL)) {
13188     str = SUB (str);
13189   }
13190   if (IS (str, FLEX_SYMBOL)) {
13191     str = SUB (str);
13192   }
13193   if (IS (str, ROW_SYMBOL)) {
13194     str = SUB (str);
13195   }
13196   t_2 = PACK (str);
13197   while (t != NO_PACK && t_2 != NO_PACK) {
13198     if (TEXT (t) == fs) {
13199       MOID_T *ret = MOID (t);
13200       if (deflex && TRIM (ret) != NO_MOID) {
13201         ret = TRIM (ret);
13202       }
13203       make_soid (y, SORT (x), ret, 0);
13204       MOID (p) = ret;
13205       NODE_PACK (SUB (p)) = t_2;
13206       return;
13207     }
13208     FORWARD (t);
13209     FORWARD (t_2);
13210   }
13211   make_soid (&d, NO_SORT, n, 0);
13212   diagnostic_node (A68_ERROR, p, ERROR_NO_FIELD, str, fs);
13213   make_soid (y, SORT (x), MODE (ERROR), 0);
13214 }
13215 
13216 /**
13217 @brief Mode check diagonal.
13218 @param p Node in syntax tree.
13219 @param x Expected soid.
13220 @param y Resulting soid.
13221 **/
13222 
13223 static void
mode_check_diagonal(NODE_T * p,SOID_T * x,SOID_T * y)13224 mode_check_diagonal (NODE_T * p, SOID_T * x, SOID_T * y)
13225 {
13226   SOID_T w, d;
13227   NODE_T *tert;
13228   MOID_T *n, *ori;
13229   int rowdim;
13230   BOOL_T is_ref;
13231   if (IS (p, TERTIARY)) {
13232     make_soid (&w, STRONG, MODE (INT), 0);
13233     mode_check_unit (p, &w, &d);
13234     if (!is_coercible_in_context (&d, &w, SAFE_DEFLEXING)) {
13235       cannot_coerce (p, MOID (&d), MOID (&w), MEEK, SAFE_DEFLEXING, 0);
13236     }
13237     tert = NEXT_NEXT (p);
13238   } else {
13239     tert = NEXT (p);
13240   }
13241   make_soid (&w, WEAK, NO_MOID, 0);
13242   mode_check_unit (tert, &w, &d);
13243   n = ori = determine_unique_mode (&d, SAFE_DEFLEXING);
13244   while (IS (n, REF_SYMBOL) && !is_ref_row (n)) {
13245     n = depref_once (n);
13246   }
13247   if (n != NO_MOID && (IS (n, FLEX_SYMBOL) || IS_REF_FLEX (n))) {
13248     if (IF_MODE_IS_WELL (n)) {
13249       diagnostic_node (A68_ERROR, p, ERROR_NO_FLEX_ARGUMENT, ori, TERTIARY);
13250     }
13251     make_soid (y, SORT (x), MODE (ERROR), 0);
13252     return;
13253   }
13254   if (n == NO_MOID || !(SLICE (DEFLEX (n)) != NO_MOID || is_ref_row (n))) {
13255     if (IF_MODE_IS_WELL (n)) {
13256       diagnostic_node (A68_ERROR, p, ERROR_NO_MATRIX, ori, TERTIARY);
13257     }
13258     make_soid (y, SORT (x), MODE (ERROR), 0);
13259     return;
13260   }
13261   if ((is_ref = is_ref_row (n)) != A68_FALSE) {
13262     rowdim = DIM (DEFLEX (SUB (n)));
13263   } else {
13264     rowdim = DIM (DEFLEX (n));
13265   }
13266   if (rowdim != 2) {
13267     diagnostic_node (A68_ERROR, p, ERROR_NO_MATRIX, ori, TERTIARY);
13268     make_soid (y, SORT (x), MODE (ERROR), 0);
13269     return;
13270   }
13271   MOID (tert) = n;
13272   if (is_ref) {
13273     n = NAME (n);
13274     ABEND (ISNT (n, REF_SYMBOL), "mode table error", PM (n));
13275   } else {
13276     n = SLICE (n);
13277   }
13278   ABEND (n == NO_MOID, "No mode in mode_check_diagonal", NO_TEXT);
13279   make_soid (y, SORT (x), n, 0);
13280 }
13281 
13282 /**
13283 @brief Mode check transpose.
13284 @param p Node in syntax tree.
13285 @param x Expected soid.
13286 @param y Resulting soid.
13287 **/
13288 
13289 static void
mode_check_transpose(NODE_T * p,SOID_T * x,SOID_T * y)13290 mode_check_transpose (NODE_T * p, SOID_T * x, SOID_T * y)
13291 {
13292   SOID_T w, d;
13293   NODE_T *tert = NEXT (p);
13294   MOID_T *n, *ori;
13295   int rowdim;
13296   BOOL_T is_ref;
13297   make_soid (&w, WEAK, NO_MOID, 0);
13298   mode_check_unit (tert, &w, &d);
13299   n = ori = determine_unique_mode (&d, SAFE_DEFLEXING);
13300   while (IS (n, REF_SYMBOL) && !is_ref_row (n)) {
13301     n = depref_once (n);
13302   }
13303   if (n != NO_MOID && (IS (n, FLEX_SYMBOL) || IS_REF_FLEX (n))) {
13304     if (IF_MODE_IS_WELL (n)) {
13305       diagnostic_node (A68_ERROR, p, ERROR_NO_FLEX_ARGUMENT, ori, TERTIARY);
13306     }
13307     make_soid (y, SORT (x), MODE (ERROR), 0);
13308     return;
13309   }
13310   if (n == NO_MOID || !(SLICE (DEFLEX (n)) != NO_MOID || is_ref_row (n))) {
13311     if (IF_MODE_IS_WELL (n)) {
13312       diagnostic_node (A68_ERROR, p, ERROR_NO_MATRIX, ori, TERTIARY);
13313     }
13314     make_soid (y, SORT (x), MODE (ERROR), 0);
13315     return;
13316   }
13317   if ((is_ref = is_ref_row (n)) != A68_FALSE) {
13318     rowdim = DIM (DEFLEX (SUB (n)));
13319   } else {
13320     rowdim = DIM (DEFLEX (n));
13321   }
13322   if (rowdim != 2) {
13323     diagnostic_node (A68_ERROR, p, ERROR_NO_MATRIX, ori, TERTIARY);
13324     make_soid (y, SORT (x), MODE (ERROR), 0);
13325     return;
13326   }
13327   MOID (tert) = n;
13328   ABEND (n == NO_MOID, "No mode in mode_check_transpose", NO_TEXT);
13329   make_soid (y, SORT (x), n, 0);
13330 }
13331 
13332 /**
13333 @brief Mode check row or column function.
13334 @param p Node in syntax tree.
13335 @param x Expected soid.
13336 @param y Resulting soid.
13337 **/
13338 
13339 static void
mode_check_row_column_function(NODE_T * p,SOID_T * x,SOID_T * y)13340 mode_check_row_column_function (NODE_T * p, SOID_T * x, SOID_T * y)
13341 {
13342   SOID_T w, d;
13343   NODE_T *tert;
13344   MOID_T *n, *ori;
13345   int rowdim;
13346   BOOL_T is_ref;
13347   if (IS (p, TERTIARY)) {
13348     make_soid (&w, STRONG, MODE (INT), 0);
13349     mode_check_unit (p, &w, &d);
13350     if (!is_coercible_in_context (&d, &w, SAFE_DEFLEXING)) {
13351       cannot_coerce (p, MOID (&d), MOID (&w), MEEK, SAFE_DEFLEXING, 0);
13352     }
13353     tert = NEXT_NEXT (p);
13354   } else {
13355     tert = NEXT (p);
13356   }
13357   make_soid (&w, WEAK, NO_MOID, 0);
13358   mode_check_unit (tert, &w, &d);
13359   n = ori = determine_unique_mode (&d, SAFE_DEFLEXING);
13360   while (IS (n, REF_SYMBOL) && !is_ref_row (n)) {
13361     n = depref_once (n);
13362   }
13363   if (n != NO_MOID && (IS (n, FLEX_SYMBOL) || IS_REF_FLEX (n))) {
13364     if (IF_MODE_IS_WELL (n)) {
13365       diagnostic_node (A68_ERROR, p, ERROR_NO_FLEX_ARGUMENT, ori, TERTIARY);
13366     }
13367     make_soid (y, SORT (x), MODE (ERROR), 0);
13368     return;
13369   }
13370   if (n == NO_MOID || !(SLICE (DEFLEX (n)) != NO_MOID || is_ref_row (n))) {
13371     if (IF_MODE_IS_WELL (n)) {
13372       diagnostic_node (A68_ERROR, p, ERROR_NO_VECTOR, ori, TERTIARY);
13373     }
13374     make_soid (y, SORT (x), MODE (ERROR), 0);
13375     return;
13376   }
13377   if ((is_ref = is_ref_row (n)) != A68_FALSE) {
13378     rowdim = DIM (DEFLEX (SUB (n)));
13379   } else {
13380     rowdim = DIM (DEFLEX (n));
13381   }
13382   if (rowdim != 1) {
13383     diagnostic_node (A68_ERROR, p, ERROR_NO_VECTOR, ori, TERTIARY);
13384     make_soid (y, SORT (x), MODE (ERROR), 0);
13385     return;
13386   }
13387   MOID (tert) = n;
13388   ABEND (n == NO_MOID, "No mode in mode_check_diagonal", NO_TEXT);
13389   make_soid (y, SORT (x), ROWED (n), 0);
13390 }
13391 
13392 /**
13393 @brief Mode check format text.
13394 @param p Node in syntax tree.
13395 **/
13396 
13397 static void
mode_check_format_text(NODE_T * p)13398 mode_check_format_text (NODE_T * p)
13399 {
13400   for (; p != NO_NODE; FORWARD (p)) {
13401     mode_check_format_text (SUB (p));
13402     if (IS (p, FORMAT_PATTERN)) {
13403       SOID_T x, y;
13404       make_soid (&x, STRONG, MODE (FORMAT), 0);
13405       mode_check_enclosed (SUB (NEXT_SUB (p)), &x, &y);
13406       if (!is_coercible_in_context (&y, &x, SAFE_DEFLEXING)) {
13407         cannot_coerce (p, MOID (&y), MOID (&x), STRONG, SAFE_DEFLEXING, ENCLOSED_CLAUSE);
13408       }
13409     } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
13410       SOID_T x, y;
13411       make_soid (&x, STRONG, MODE (ROW_INT), 0);
13412       mode_check_enclosed (SUB (NEXT_SUB (p)), &x, &y);
13413       if (!is_coercible_in_context (&y, &x, SAFE_DEFLEXING)) {
13414         cannot_coerce (p, MOID (&y), MOID (&x), STRONG, SAFE_DEFLEXING, ENCLOSED_CLAUSE);
13415       }
13416     } else if (IS (p, DYNAMIC_REPLICATOR)) {
13417       SOID_T x, y;
13418       make_soid (&x, STRONG, MODE (INT), 0);
13419       mode_check_enclosed (SUB (NEXT_SUB (p)), &x, &y);
13420       if (!is_coercible_in_context (&y, &x, SAFE_DEFLEXING)) {
13421         cannot_coerce (p, MOID (&y), MOID (&x), STRONG, SAFE_DEFLEXING, ENCLOSED_CLAUSE);
13422       }
13423     }
13424   }
13425 }
13426 
13427 /**
13428 @brief Mode check unit.
13429 @param p Node in syntax tree.
13430 @param x Expected soid.
13431 @param y Resulting soid.
13432 **/
13433 
13434 static void
mode_check_unit(NODE_T * p,SOID_T * x,SOID_T * y)13435 mode_check_unit (NODE_T * p, SOID_T * x, SOID_T * y)
13436 {
13437   if (p == NO_NODE) {
13438     return;
13439   } else if (is_one_of (p, UNIT, TERTIARY, SECONDARY, PRIMARY, STOP)) {
13440     mode_check_unit (SUB (p), x, y);
13441 /* Ex primary */
13442   } else if (IS (p, SPECIFICATION)) {
13443     ATTRIBUTE (p) = mode_check_specification (SUB (p), x, y);
13444     warn_for_voiding (p, x, y, ATTRIBUTE (p));
13445   } else if (IS (p, CAST)) {
13446     mode_check_cast (SUB (p), x, y);
13447     warn_for_voiding (p, x, y, CAST);
13448   } else if (IS (p, DENOTATION)) {
13449     make_soid (y, SORT (x), MOID (SUB (p)), 0);
13450     warn_for_voiding (p, x, y, DENOTATION);
13451   } else if (IS (p, IDENTIFIER)) {
13452     if ((TAX (p) == NO_TAG) && (MOID (p) == NO_MOID)) {
13453       int att = first_tag_global (TABLE (p), NSYMBOL (p));
13454       if (att == STOP) {
13455         (void) add_tag (TABLE (p), IDENTIFIER, p, MODE (ERROR), NORMAL_IDENTIFIER);
13456         diagnostic_node (A68_ERROR, p, ERROR_UNDECLARED_TAG);
13457         MOID (p) = MODE (ERROR);
13458       } else {
13459         TAG_T *z = find_tag_global (TABLE (p), att, NSYMBOL (p));
13460         if (att == IDENTIFIER && z != NO_TAG) {
13461           MOID (p) = MOID (z);
13462         } else {
13463           (void) add_tag (TABLE (p), IDENTIFIER, p, MODE (ERROR), NORMAL_IDENTIFIER);
13464           diagnostic_node (A68_ERROR, p, ERROR_UNDECLARED_TAG);
13465           MOID (p) = MODE (ERROR);
13466         }
13467       }
13468     }
13469     make_soid (y, SORT (x), MOID (p), 0);
13470     warn_for_voiding (p, x, y, IDENTIFIER);
13471   } else if (IS (p, ENCLOSED_CLAUSE)) {
13472     mode_check_enclosed (SUB (p), x, y);
13473   } else if (IS (p, FORMAT_TEXT)) {
13474     mode_check_format_text (p);
13475     make_soid (y, SORT (x), MODE (FORMAT), 0);
13476     warn_for_voiding (p, x, y, FORMAT_TEXT);
13477 /* Ex secondary */
13478   } else if (IS (p, GENERATOR)) {
13479     mode_check_declarer (SUB (p));
13480     make_soid (y, SORT (x), MOID (SUB (p)), 0);
13481     warn_for_voiding (p, x, y, GENERATOR);
13482   } else if (IS (p, SELECTION)) {
13483     mode_check_selection (SUB (p), x, y);
13484     warn_for_voiding (p, x, y, SELECTION);
13485 /* Ex tertiary */
13486   } else if (IS (p, NIHIL)) {
13487     make_soid (y, STRONG, MODE (HIP), 0);
13488   } else if (IS (p, FORMULA)) {
13489     mode_check_formula (p, x, y);
13490     if (ISNT (MOID (y), REF_SYMBOL)) {
13491       warn_for_voiding (p, x, y, FORMULA);
13492     }
13493   } else if (IS (p, DIAGONAL_FUNCTION)) {
13494     mode_check_diagonal (SUB (p), x, y);
13495     warn_for_voiding (p, x, y, DIAGONAL_FUNCTION);
13496   } else if (IS (p, TRANSPOSE_FUNCTION)) {
13497     mode_check_transpose (SUB (p), x, y);
13498     warn_for_voiding (p, x, y, TRANSPOSE_FUNCTION);
13499   } else if (IS (p, ROW_FUNCTION)) {
13500     mode_check_row_column_function (SUB (p), x, y);
13501     warn_for_voiding (p, x, y, ROW_FUNCTION);
13502   } else if (IS (p, COLUMN_FUNCTION)) {
13503     mode_check_row_column_function (SUB (p), x, y);
13504     warn_for_voiding (p, x, y, COLUMN_FUNCTION);
13505 /* Ex unit */
13506   } else if (is_one_of (p, JUMP, SKIP, STOP)) {
13507     make_soid (y, STRONG, MODE (HIP), 0);
13508   } else if (IS (p, ASSIGNATION)) {
13509     mode_check_assignation (SUB (p), x, y);
13510   } else if (IS (p, IDENTITY_RELATION)) {
13511     mode_check_identity_relation (SUB (p), x, y);
13512     warn_for_voiding (p, x, y, IDENTITY_RELATION);
13513   } else if (IS (p, ROUTINE_TEXT)) {
13514     mode_check_routine_text (SUB (p), y);
13515     make_soid (y, SORT (x), MOID (p), 0);
13516     warn_for_voiding (p, x, y, ROUTINE_TEXT);
13517   } else if (IS (p, ASSERTION)) {
13518     mode_check_assertion (SUB (p));
13519     make_soid (y, STRONG, MODE (VOID), 0);
13520   } else if (IS (p, AND_FUNCTION)) {
13521     mode_check_bool_function (SUB (p), x, y);
13522     warn_for_voiding (p, x, y, AND_FUNCTION);
13523   } else if (IS (p, OR_FUNCTION)) {
13524     mode_check_bool_function (SUB (p), x, y);
13525     warn_for_voiding (p, x, y, OR_FUNCTION);
13526   } else if (IS (p, CODE_CLAUSE)) {
13527     make_soid (y, STRONG, MODE (HIP), 0);
13528   }
13529   MOID (p) = MOID (y);
13530 }
13531 
13532 /**
13533 @brief Coerce bounds.
13534 @param p Node in syntax tree.
13535 **/
13536 
13537 static void
coerce_bounds(NODE_T * p)13538 coerce_bounds (NODE_T * p)
13539 {
13540   for (; p != NO_NODE; FORWARD (p)) {
13541     if (IS (p, UNIT)) {
13542       SOID_T q;
13543       make_soid (&q, MEEK, MODE (INT), 0);
13544       coerce_unit (p, &q);
13545     } else {
13546       coerce_bounds (SUB (p));
13547     }
13548   }
13549 }
13550 
13551 /**
13552 @brief Coerce declarer.
13553 @param p Node in syntax tree.
13554 **/
13555 
13556 static void
coerce_declarer(NODE_T * p)13557 coerce_declarer (NODE_T * p)
13558 {
13559   for (; p != NO_NODE; FORWARD (p)) {
13560     if (IS (p, BOUNDS)) {
13561       coerce_bounds (SUB (p));
13562     } else {
13563       coerce_declarer (SUB (p));
13564     }
13565   }
13566 }
13567 
13568 /**
13569 @brief Coerce identity declaration.
13570 @param p Node in syntax tree.
13571 **/
13572 
13573 static void
coerce_identity_declaration(NODE_T * p)13574 coerce_identity_declaration (NODE_T * p)
13575 {
13576   if (p != NO_NODE) {
13577     switch (ATTRIBUTE (p)) {
13578     case DECLARER:
13579       {
13580         coerce_declarer (SUB (p));
13581         coerce_identity_declaration (NEXT (p));
13582         break;
13583       }
13584     case DEFINING_IDENTIFIER:
13585       {
13586         SOID_T q;
13587         make_soid (&q, STRONG, MOID (p), 0);
13588         coerce_unit (NEXT_NEXT (p), &q);
13589         break;
13590       }
13591     default:
13592       {
13593         coerce_identity_declaration (SUB (p));
13594         coerce_identity_declaration (NEXT (p));
13595         break;
13596       }
13597     }
13598   }
13599 }
13600 
13601 /**
13602 @brief Coerce variable declaration.
13603 @param p Node in syntax tree.
13604 **/
13605 
13606 static void
coerce_variable_declaration(NODE_T * p)13607 coerce_variable_declaration (NODE_T * p)
13608 {
13609   if (p != NO_NODE) {
13610     switch (ATTRIBUTE (p)) {
13611     case DECLARER:
13612       {
13613         coerce_declarer (SUB (p));
13614         coerce_variable_declaration (NEXT (p));
13615         break;
13616       }
13617     case DEFINING_IDENTIFIER:
13618       {
13619         if (whether (p, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, UNIT, STOP)) {
13620           SOID_T q;
13621           make_soid (&q, STRONG, SUB_MOID (p), 0);
13622           coerce_unit (NEXT_NEXT (p), &q);
13623           break;
13624         }
13625       }
13626     default:
13627       {
13628         coerce_variable_declaration (SUB (p));
13629         coerce_variable_declaration (NEXT (p));
13630         break;
13631       }
13632     }
13633   }
13634 }
13635 
13636 /**
13637 @brief Coerce routine text.
13638 @param p Node in syntax tree.
13639 **/
13640 
13641 static void
coerce_routine_text(NODE_T * p)13642 coerce_routine_text (NODE_T * p)
13643 {
13644   SOID_T w;
13645   if (IS (p, PARAMETER_PACK)) {
13646     FORWARD (p);
13647   }
13648   make_soid (&w, STRONG, MOID (p), 0);
13649   coerce_unit (NEXT_NEXT (p), &w);
13650 }
13651 
13652 /**
13653 @brief Coerce proc declaration.
13654 @param p Node in syntax tree.
13655 **/
13656 
13657 static void
coerce_proc_declaration(NODE_T * p)13658 coerce_proc_declaration (NODE_T * p)
13659 {
13660   if (p == NO_NODE) {
13661     return;
13662   } else if (IS (p, ROUTINE_TEXT)) {
13663     coerce_routine_text (SUB (p));
13664   } else {
13665     coerce_proc_declaration (SUB (p));
13666     coerce_proc_declaration (NEXT (p));
13667   }
13668 }
13669 
13670 /**
13671 @brief Coerce_op_declaration.
13672 @param p Node in syntax tree.
13673 **/
13674 
13675 static void
coerce_op_declaration(NODE_T * p)13676 coerce_op_declaration (NODE_T * p)
13677 {
13678   if (p == NO_NODE) {
13679     return;
13680   } else if (IS (p, DEFINING_OPERATOR)) {
13681     SOID_T q;
13682     make_soid (&q, STRONG, MOID (p), 0);
13683     coerce_unit (NEXT_NEXT (p), &q);
13684   } else {
13685     coerce_op_declaration (SUB (p));
13686     coerce_op_declaration (NEXT (p));
13687   }
13688 }
13689 
13690 /**
13691 @brief Coerce brief op declaration.
13692 @param p Node in syntax tree.
13693 **/
13694 
13695 static void
coerce_brief_op_declaration(NODE_T * p)13696 coerce_brief_op_declaration (NODE_T * p)
13697 {
13698   if (p == NO_NODE) {
13699     return;
13700   } else if (IS (p, DEFINING_OPERATOR)) {
13701     coerce_routine_text (SUB (NEXT_NEXT (p)));
13702   } else {
13703     coerce_brief_op_declaration (SUB (p));
13704     coerce_brief_op_declaration (NEXT (p));
13705   }
13706 }
13707 
13708 /**
13709 @brief Coerce declaration list.
13710 @param p Node in syntax tree.
13711 **/
13712 
13713 static void
coerce_declaration_list(NODE_T * p)13714 coerce_declaration_list (NODE_T * p)
13715 {
13716   if (p != NO_NODE) {
13717     switch (ATTRIBUTE (p)) {
13718     case IDENTITY_DECLARATION:
13719       {
13720         coerce_identity_declaration (SUB (p));
13721         break;
13722       }
13723     case VARIABLE_DECLARATION:
13724       {
13725         coerce_variable_declaration (SUB (p));
13726         break;
13727       }
13728     case MODE_DECLARATION:
13729       {
13730         coerce_declarer (SUB (p));
13731         break;
13732       }
13733     case PROCEDURE_DECLARATION:
13734     case PROCEDURE_VARIABLE_DECLARATION:
13735       {
13736         coerce_proc_declaration (SUB (p));
13737         break;
13738       }
13739     case BRIEF_OPERATOR_DECLARATION:
13740       {
13741         coerce_brief_op_declaration (SUB (p));
13742         break;
13743       }
13744     case OPERATOR_DECLARATION:
13745       {
13746         coerce_op_declaration (SUB (p));
13747         break;
13748       }
13749     default:
13750       {
13751         coerce_declaration_list (SUB (p));
13752         coerce_declaration_list (NEXT (p));
13753         break;
13754       }
13755     }
13756   }
13757 }
13758 
13759 /**
13760 @brief Coerce serial.
13761 @param p Node in syntax tree.
13762 @param q Soid.
13763 @param k Whether k yields value other than VOID.
13764 **/
13765 
13766 static void
coerce_serial(NODE_T * p,SOID_T * q,BOOL_T k)13767 coerce_serial (NODE_T * p, SOID_T * q, BOOL_T k)
13768 {
13769   if (p == NO_NODE) {
13770     return;
13771   } else if (IS (p, INITIALISER_SERIES)) {
13772     coerce_serial (SUB (p), q, A68_FALSE);
13773     coerce_serial (NEXT (p), q, k);
13774   } else if (IS (p, DECLARATION_LIST)) {
13775     coerce_declaration_list (SUB (p));
13776   } else if (is_one_of (p, LABEL, SEMI_SYMBOL, EXIT_SYMBOL, STOP)) {
13777     coerce_serial (NEXT (p), q, k);
13778   } else if (is_one_of (p, SERIAL_CLAUSE, ENQUIRY_CLAUSE, STOP)) {
13779     NODE_T *z = NEXT (p);
13780     if (z != NO_NODE) {
13781       if (IS (z, EXIT_SYMBOL) || IS (z, END_SYMBOL) || IS (z, CLOSE_SYMBOL) || IS (z, OCCA_SYMBOL)) {
13782         coerce_serial (SUB (p), q, A68_TRUE);
13783       } else {
13784         coerce_serial (SUB (p), q, A68_FALSE);
13785       }
13786     } else {
13787       coerce_serial (SUB (p), q, A68_TRUE);
13788     }
13789     coerce_serial (NEXT (p), q, k);
13790   } else if (IS (p, LABELED_UNIT)) {
13791     coerce_serial (SUB (p), q, k);
13792   } else if (IS (p, UNIT)) {
13793     if (k) {
13794       coerce_unit (p, q);
13795     } else {
13796       SOID_T strongvoid;
13797       make_soid (&strongvoid, STRONG, MODE (VOID), 0);
13798       coerce_unit (p, &strongvoid);
13799     }
13800   }
13801 }
13802 
13803 /**
13804 @brief Coerce closed.
13805 @param p Node in syntax tree.
13806 @param q Soid.
13807 **/
13808 
13809 static void
coerce_closed(NODE_T * p,SOID_T * q)13810 coerce_closed (NODE_T * p, SOID_T * q)
13811 {
13812   if (IS (p, SERIAL_CLAUSE)) {
13813     coerce_serial (p, q, A68_TRUE);
13814   } else if (is_one_of (p, OPEN_SYMBOL, BEGIN_SYMBOL, STOP)) {
13815     coerce_closed (NEXT (p), q);
13816   }
13817 }
13818 
13819 /**
13820 @brief Coerce conditional.
13821 @param p Node in syntax tree.
13822 @param q Soid.
13823 **/
13824 
13825 static void
coerce_conditional(NODE_T * p,SOID_T * q)13826 coerce_conditional (NODE_T * p, SOID_T * q)
13827 {
13828   SOID_T w;
13829   make_soid (&w, MEEK, MODE (BOOL), 0);
13830   coerce_serial (NEXT_SUB (p), &w, A68_TRUE);
13831   FORWARD (p);
13832   coerce_serial (NEXT_SUB (p), q, A68_TRUE);
13833   if ((FORWARD (p)) != NO_NODE) {
13834     if (is_one_of (p, ELSE_PART, CHOICE, STOP)) {
13835       coerce_serial (NEXT_SUB (p), q, A68_TRUE);
13836     } else if (is_one_of (p, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
13837       coerce_conditional (SUB (p), q);
13838     }
13839   }
13840 }
13841 
13842 /**
13843 @brief Coerce unit list.
13844 @param p Node in syntax tree.
13845 @param q Soid.
13846 **/
13847 
13848 static void
coerce_unit_list(NODE_T * p,SOID_T * q)13849 coerce_unit_list (NODE_T * p, SOID_T * q)
13850 {
13851   if (p == NO_NODE) {
13852     return;
13853   } else if (IS (p, UNIT_LIST)) {
13854     coerce_unit_list (SUB (p), q);
13855     coerce_unit_list (NEXT (p), q);
13856   } else if (is_one_of (p, OPEN_SYMBOL, BEGIN_SYMBOL, COMMA_SYMBOL, STOP)) {
13857     coerce_unit_list (NEXT (p), q);
13858   } else if (IS (p, UNIT)) {
13859     coerce_unit (p, q);
13860     coerce_unit_list (NEXT (p), q);
13861   }
13862 }
13863 
13864 /**
13865 @brief Coerce int case.
13866 @param p Node in syntax tree.
13867 @param q Soid.
13868 **/
13869 
13870 static void
coerce_int_case(NODE_T * p,SOID_T * q)13871 coerce_int_case (NODE_T * p, SOID_T * q)
13872 {
13873   SOID_T w;
13874   make_soid (&w, MEEK, MODE (INT), 0);
13875   coerce_serial (NEXT_SUB (p), &w, A68_TRUE);
13876   FORWARD (p);
13877   coerce_unit_list (NEXT_SUB (p), q);
13878   if ((FORWARD (p)) != NO_NODE) {
13879     if (is_one_of (p, OUT_PART, CHOICE, STOP)) {
13880       coerce_serial (NEXT_SUB (p), q, A68_TRUE);
13881     } else if (is_one_of (p, CASE_OUSE_PART, BRIEF_OUSE_PART, STOP)) {
13882       coerce_int_case (SUB (p), q);
13883     }
13884   }
13885 }
13886 
13887 /**
13888 @brief Coerce spec unit list.
13889 @param p Node in syntax tree.
13890 @param q Soid.
13891 **/
13892 
13893 static void
coerce_spec_unit_list(NODE_T * p,SOID_T * q)13894 coerce_spec_unit_list (NODE_T * p, SOID_T * q)
13895 {
13896   for (; p != NO_NODE; FORWARD (p)) {
13897     if (is_one_of (p, SPECIFIED_UNIT_LIST, SPECIFIED_UNIT, STOP)) {
13898       coerce_spec_unit_list (SUB (p), q);
13899     } else if (IS (p, UNIT)) {
13900       coerce_unit (p, q);
13901     }
13902   }
13903 }
13904 
13905 /**
13906 @brief Coerce united case.
13907 @param p Node in syntax tree.
13908 @param q Soid.
13909 **/
13910 
13911 static void
coerce_united_case(NODE_T * p,SOID_T * q)13912 coerce_united_case (NODE_T * p, SOID_T * q)
13913 {
13914   SOID_T w;
13915   make_soid (&w, MEEK, MOID (SUB (p)), 0);
13916   coerce_serial (NEXT_SUB (p), &w, A68_TRUE);
13917   FORWARD (p);
13918   coerce_spec_unit_list (NEXT_SUB (p), q);
13919   if ((FORWARD (p)) != NO_NODE) {
13920     if (is_one_of (p, OUT_PART, CHOICE, STOP)) {
13921       coerce_serial (NEXT_SUB (p), q, A68_TRUE);
13922     } else if (is_one_of (p, CONFORMITY_OUSE_PART, BRIEF_CONFORMITY_OUSE_PART, STOP)) {
13923       coerce_united_case (SUB (p), q);
13924     }
13925   }
13926 }
13927 
13928 /**
13929 @brief Coerce loop.
13930 @param p Node in syntax tree.
13931 **/
13932 
13933 static void
coerce_loop(NODE_T * p)13934 coerce_loop (NODE_T * p)
13935 {
13936   if (IS (p, FOR_PART)) {
13937     coerce_loop (NEXT (p));
13938   } else if (is_one_of (p, FROM_PART, BY_PART, TO_PART, STOP)) {
13939     SOID_T w;
13940     make_soid (&w, MEEK, MODE (INT), 0);
13941     coerce_unit (NEXT_SUB (p), &w);
13942     coerce_loop (NEXT (p));
13943   } else if (IS (p, WHILE_PART)) {
13944     SOID_T w;
13945     make_soid (&w, MEEK, MODE (BOOL), 0);
13946     coerce_serial (NEXT_SUB (p), &w, A68_TRUE);
13947     coerce_loop (NEXT (p));
13948   } else if (is_one_of (p, DO_PART, ALT_DO_PART, STOP)) {
13949     SOID_T w;
13950     NODE_T *do_p = NEXT_SUB (p), *un_p;
13951     make_soid (&w, STRONG, MODE (VOID), 0);
13952     coerce_serial (do_p, &w, A68_TRUE);
13953     if (IS (do_p, SERIAL_CLAUSE)) {
13954       un_p = NEXT (do_p);
13955     } else {
13956       un_p = do_p;
13957     }
13958     if (un_p != NO_NODE && IS (un_p, UNTIL_PART)) {
13959       SOID_T sw;
13960       make_soid (&sw, MEEK, MODE (BOOL), 0);
13961       coerce_serial (NEXT_SUB (un_p), &sw, A68_TRUE);
13962     }
13963   }
13964 }
13965 
13966 /**
13967 @brief Coerce struct display.
13968 @param r Pack.
13969 @param p Node in syntax tree.
13970 **/
13971 
13972 static void
coerce_struct_display(PACK_T ** r,NODE_T * p)13973 coerce_struct_display (PACK_T ** r, NODE_T * p)
13974 {
13975   if (p == NO_NODE) {
13976     return;
13977   } else if (IS (p, UNIT_LIST)) {
13978     coerce_struct_display (r, SUB (p));
13979     coerce_struct_display (r, NEXT (p));
13980   } else if (is_one_of (p, OPEN_SYMBOL, BEGIN_SYMBOL, COMMA_SYMBOL, STOP)) {
13981     coerce_struct_display (r, NEXT (p));
13982   } else if (IS (p, UNIT)) {
13983     SOID_T s;
13984     make_soid (&s, STRONG, MOID (*r), 0);
13985     coerce_unit (p, &s);
13986     FORWARD (*r);
13987     coerce_struct_display (r, NEXT (p));
13988   }
13989 }
13990 
13991 /**
13992 @brief Coerce collateral.
13993 @param p Node in syntax tree.
13994 @param q Soid.
13995 **/
13996 
13997 static void
coerce_collateral(NODE_T * p,SOID_T * q)13998 coerce_collateral (NODE_T * p, SOID_T * q)
13999 {
14000   if (!(whether (p, BEGIN_SYMBOL, END_SYMBOL, STOP) || whether (p, OPEN_SYMBOL, CLOSE_SYMBOL, STOP))) {
14001     if (IS (MOID (q), STRUCT_SYMBOL)) {
14002       PACK_T *t = PACK (MOID (q));
14003       coerce_struct_display (&t, p);
14004     } else if (IS (MOID (q), FLEX_SYMBOL)) {
14005       SOID_T w;
14006       make_soid (&w, STRONG, SLICE (SUB_MOID (q)), 0);
14007       coerce_unit_list (p, &w);
14008     } else if (IS (MOID (q), ROW_SYMBOL)) {
14009       SOID_T w;
14010       make_soid (&w, STRONG, SLICE (MOID (q)), 0);
14011       coerce_unit_list (p, &w);
14012     } else {
14013 /* if (MOID (q) != MODE (VOID)) */
14014       coerce_unit_list (p, q);
14015     }
14016   }
14017 }
14018 
14019 /**
14020 @brief Coerce_enclosed.
14021 @param p Node in syntax tree.
14022 @param q Soid.
14023 **/
14024 
14025 void
coerce_enclosed(NODE_T * p,SOID_T * q)14026 coerce_enclosed (NODE_T * p, SOID_T * q)
14027 {
14028   if (IS (p, ENCLOSED_CLAUSE)) {
14029     coerce_enclosed (SUB (p), q);
14030   } else if (IS (p, CLOSED_CLAUSE)) {
14031     coerce_closed (SUB (p), q);
14032   } else if (IS (p, COLLATERAL_CLAUSE)) {
14033     coerce_collateral (SUB (p), q);
14034   } else if (IS (p, PARALLEL_CLAUSE)) {
14035     coerce_collateral (SUB (NEXT_SUB (p)), q);
14036   } else if (IS (p, CONDITIONAL_CLAUSE)) {
14037     coerce_conditional (SUB (p), q);
14038   } else if (IS (p, CASE_CLAUSE)) {
14039     coerce_int_case (SUB (p), q);
14040   } else if (IS (p, CONFORMITY_CLAUSE)) {
14041     coerce_united_case (SUB (p), q);
14042   } else if (IS (p, LOOP_CLAUSE)) {
14043     coerce_loop (SUB (p));
14044   }
14045   MOID (p) = depref_rows (MOID (p), MOID (q));
14046 }
14047 
14048 /**
14049 @brief Get monad moid.
14050 @param p Node in syntax tree.
14051 **/
14052 
14053 static MOID_T *
get_monad_moid(NODE_T * p)14054 get_monad_moid (NODE_T * p)
14055 {
14056   if (TAX (p) != NO_TAG && TAX (p) != error_tag) {
14057     MOID (p) = MOID (TAX (p));
14058     return (MOID (PACK (MOID (p))));
14059   } else {
14060     return (MODE (ERROR));
14061   }
14062 }
14063 
14064 /**
14065 @brief Coerce monad oper.
14066 @param p Node in syntax tree.
14067 @param q Soid.
14068 **/
14069 
14070 static void
coerce_monad_oper(NODE_T * p,SOID_T * q)14071 coerce_monad_oper (NODE_T * p, SOID_T * q)
14072 {
14073   if (p != NO_NODE) {
14074     SOID_T z;
14075     make_soid (&z, FIRM, MOID (PACK (MOID (TAX (p)))), 0);
14076     INSERT_COERCIONS (NEXT (p), MOID (q), &z);
14077   }
14078 }
14079 
14080 /**
14081 @brief Coerce monad formula.
14082 @param p Node in syntax tree.
14083 **/
14084 
14085 static void
coerce_monad_formula(NODE_T * p)14086 coerce_monad_formula (NODE_T * p)
14087 {
14088   SOID_T e;
14089   make_soid (&e, STRONG, get_monad_moid (p), 0);
14090   coerce_operand (NEXT (p), &e);
14091   coerce_monad_oper (p, &e);
14092 }
14093 
14094 /**
14095 @brief Coerce operand.
14096 @param p Node in syntax tree.
14097 @param q Soid.
14098 **/
14099 
14100 static void
coerce_operand(NODE_T * p,SOID_T * q)14101 coerce_operand (NODE_T * p, SOID_T * q)
14102 {
14103   if (IS (p, MONADIC_FORMULA)) {
14104     coerce_monad_formula (SUB (p));
14105     if (MOID (p) != MOID (q)) {
14106       make_sub (p, p, FORMULA);
14107       INSERT_COERCIONS (p, MOID (p), q);
14108       make_sub (p, p, TERTIARY);
14109     }
14110     MOID (p) = depref_rows (MOID (p), MOID (q));
14111   } else if (IS (p, FORMULA)) {
14112     coerce_formula (SUB (p), q);
14113     INSERT_COERCIONS (p, MOID (p), q);
14114     MOID (p) = depref_rows (MOID (p), MOID (q));
14115   } else if (IS (p, SECONDARY)) {
14116     coerce_unit (SUB (p), q);
14117     MOID (p) = MOID (SUB (p));
14118   }
14119 }
14120 
14121 /**
14122 @brief Coerce formula.
14123 @param p Node in syntax tree.
14124 @param q Soid.
14125 **/
14126 
14127 static void
coerce_formula(NODE_T * p,SOID_T * q)14128 coerce_formula (NODE_T * p, SOID_T * q)
14129 {
14130   (void) q;
14131   if (IS (p, MONADIC_FORMULA) && NEXT (p) == NO_NODE) {
14132     coerce_monad_formula (SUB (p));
14133   } else {
14134     if (TAX (NEXT (p)) != NO_TAG && TAX (NEXT (p)) != error_tag) {
14135       SOID_T s;
14136       NODE_T *op = NEXT (p), *nq = NEXT_NEXT (p);
14137       MOID_T *w = MOID (op);
14138       MOID_T *u = MOID (PACK (w)), *v = MOID (NEXT (PACK (w)));
14139       make_soid (&s, STRONG, u, 0);
14140       coerce_operand (p, &s);
14141       make_soid (&s, STRONG, v, 0);
14142       coerce_operand (nq, &s);
14143     }
14144   }
14145 }
14146 
14147 /**
14148 @brief Coerce assignation.
14149 @param p Node in syntax tree.
14150 **/
14151 
14152 static void
coerce_assignation(NODE_T * p)14153 coerce_assignation (NODE_T * p)
14154 {
14155   SOID_T w;
14156   make_soid (&w, SOFT, MOID (p), 0);
14157   coerce_unit (SUB (p), &w);
14158   make_soid (&w, STRONG, SUB_MOID (p), 0);
14159   coerce_unit (NEXT_NEXT (p), &w);
14160 }
14161 
14162 /**
14163 @brief Coerce relation.
14164 @param p Node in syntax tree.
14165 **/
14166 
14167 static void
coerce_relation(NODE_T * p)14168 coerce_relation (NODE_T * p)
14169 {
14170   SOID_T w;
14171   make_soid (&w, STRONG, MOID (p), 0);
14172   coerce_unit (SUB (p), &w);
14173   make_soid (&w, STRONG, MOID (NEXT_NEXT (p)), 0);
14174   coerce_unit (SUB (NEXT_NEXT (p)), &w);
14175 }
14176 
14177 /**
14178 @brief Coerce bool function.
14179 @param p Node in syntax tree.
14180 **/
14181 
14182 static void
coerce_bool_function(NODE_T * p)14183 coerce_bool_function (NODE_T * p)
14184 {
14185   SOID_T w;
14186   make_soid (&w, STRONG, MODE (BOOL), 0);
14187   coerce_unit (SUB (p), &w);
14188   coerce_unit (SUB (NEXT_NEXT (p)), &w);
14189 }
14190 
14191 /**
14192 @brief Coerce assertion.
14193 @param p Node in syntax tree.
14194 **/
14195 
14196 static void
coerce_assertion(NODE_T * p)14197 coerce_assertion (NODE_T * p)
14198 {
14199   SOID_T w;
14200   make_soid (&w, MEEK, MODE (BOOL), 0);
14201   coerce_enclosed (SUB_NEXT (p), &w);
14202 }
14203 
14204 /**
14205 @brief Coerce selection.
14206 @param p Node in syntax tree.
14207 **/
14208 
14209 static void
coerce_selection(NODE_T * p)14210 coerce_selection (NODE_T * p)
14211 {
14212   SOID_T w;
14213   make_soid (&w, /* WEAK */ STRONG, MOID (NEXT (p)), 0);
14214   coerce_unit (SUB_NEXT (p), &w);
14215 }
14216 
14217 /**
14218 @brief Coerce cast.
14219 @param p Node in syntax tree.
14220 **/
14221 
14222 static void
coerce_cast(NODE_T * p)14223 coerce_cast (NODE_T * p)
14224 {
14225   SOID_T w;
14226   coerce_declarer (p);
14227   make_soid (&w, STRONG, MOID (p), 0);
14228   coerce_enclosed (NEXT (p), &w);
14229 }
14230 
14231 /**
14232 @brief Coerce argument list.
14233 @param r Pack.
14234 @param p Node in syntax tree.
14235 **/
14236 
14237 static void
coerce_argument_list(PACK_T ** r,NODE_T * p)14238 coerce_argument_list (PACK_T ** r, NODE_T * p)
14239 {
14240   for (; p != NO_NODE; FORWARD (p)) {
14241     if (IS (p, ARGUMENT_LIST)) {
14242       coerce_argument_list (r, SUB (p));
14243     } else if (IS (p, UNIT)) {
14244       SOID_T s;
14245       make_soid (&s, STRONG, MOID (*r), 0);
14246       coerce_unit (p, &s);
14247       FORWARD (*r);
14248     } else if (IS (p, TRIMMER)) {
14249       FORWARD (*r);
14250     }
14251   }
14252 }
14253 
14254 /**
14255 @brief Coerce call.
14256 @param p Node in syntax tree.
14257 **/
14258 
14259 static void
coerce_call(NODE_T * p)14260 coerce_call (NODE_T * p)
14261 {
14262   MOID_T *proc = MOID (p);
14263   SOID_T w;
14264   PACK_T *t;
14265   make_soid (&w, MEEK, proc, 0);
14266   coerce_unit (SUB (p), &w);
14267   FORWARD (p);
14268   t = PACK (proc);
14269   coerce_argument_list (&t, SUB (p));
14270 }
14271 
14272 /**
14273 @brief Coerce meek int.
14274 @param p Node in syntax tree.
14275 **/
14276 
14277 static void
coerce_meek_int(NODE_T * p)14278 coerce_meek_int (NODE_T * p)
14279 {
14280   SOID_T x;
14281   make_soid (&x, MEEK, MODE (INT), 0);
14282   coerce_unit (p, &x);
14283 }
14284 
14285 /**
14286 @brief Coerce trimmer.
14287 @param p Node in syntax tree.
14288 **/
14289 
14290 static void
coerce_trimmer(NODE_T * p)14291 coerce_trimmer (NODE_T * p)
14292 {
14293   if (p != NO_NODE) {
14294     if (IS (p, UNIT)) {
14295       coerce_meek_int (p);
14296       coerce_trimmer (NEXT (p));
14297     } else {
14298       coerce_trimmer (NEXT (p));
14299     }
14300   }
14301 }
14302 
14303 /**
14304 @brief Coerce indexer.
14305 @param p Node in syntax tree.
14306 **/
14307 
14308 static void
coerce_indexer(NODE_T * p)14309 coerce_indexer (NODE_T * p)
14310 {
14311   if (p != NO_NODE) {
14312     if (IS (p, TRIMMER)) {
14313       coerce_trimmer (SUB (p));
14314     } else if (IS (p, UNIT)) {
14315       coerce_meek_int (p);
14316     } else {
14317       coerce_indexer (SUB (p));
14318       coerce_indexer (NEXT (p));
14319     }
14320   }
14321 }
14322 
14323 /**
14324 @brief Coerce_slice.
14325 @param p Node in syntax tree.
14326 **/
14327 
14328 static void
coerce_slice(NODE_T * p)14329 coerce_slice (NODE_T * p)
14330 {
14331   SOID_T w;
14332   MOID_T *row;
14333   row = MOID (p);
14334   make_soid (&w, /* WEAK */ STRONG, row, 0);
14335   coerce_unit (SUB (p), &w);
14336   coerce_indexer (SUB_NEXT (p));
14337 }
14338 
14339 /**
14340 @brief Mode coerce diagonal.
14341 @param p Node in syntax tree.
14342 **/
14343 
14344 static void
coerce_diagonal(NODE_T * p)14345 coerce_diagonal (NODE_T * p)
14346 {
14347   SOID_T w;
14348   if (IS (p, TERTIARY)) {
14349     make_soid (&w, MEEK, MODE (INT), 0);
14350     coerce_unit (SUB (p), &w);
14351     FORWARD (p);
14352   }
14353   make_soid (&w, /* WEAK */ STRONG, MOID (NEXT (p)), 0);
14354   coerce_unit (SUB_NEXT (p), &w);
14355 }
14356 
14357 /**
14358 @brief Mode coerce transpose.
14359 @param p Node in syntax tree.
14360 **/
14361 
14362 static void
coerce_transpose(NODE_T * p)14363 coerce_transpose (NODE_T * p)
14364 {
14365   SOID_T w;
14366   make_soid (&w, /* WEAK */ STRONG, MOID (NEXT (p)), 0);
14367   coerce_unit (SUB_NEXT (p), &w);
14368 }
14369 
14370 /**
14371 @brief Mode coerce row or column function.
14372 @param p Node in syntax tree.
14373 **/
14374 
14375 static void
coerce_row_column_function(NODE_T * p)14376 coerce_row_column_function (NODE_T * p)
14377 {
14378   SOID_T w;
14379   if (IS (p, TERTIARY)) {
14380     make_soid (&w, MEEK, MODE (INT), 0);
14381     coerce_unit (SUB (p), &w);
14382     FORWARD (p);
14383   }
14384   make_soid (&w, /* WEAK */ STRONG, MOID (NEXT (p)), 0);
14385   coerce_unit (SUB_NEXT (p), &w);
14386 }
14387 
14388 /**
14389 @brief Coerce format text.
14390 @param p Node in syntax tree.
14391 **/
14392 
14393 static void
coerce_format_text(NODE_T * p)14394 coerce_format_text (NODE_T * p)
14395 {
14396   for (; p != NO_NODE; FORWARD (p)) {
14397     coerce_format_text (SUB (p));
14398     if (IS (p, FORMAT_PATTERN)) {
14399       SOID_T x;
14400       make_soid (&x, STRONG, MODE (FORMAT), 0);
14401       coerce_enclosed (SUB (NEXT_SUB (p)), &x);
14402     } else if (IS (p, GENERAL_PATTERN) && NEXT_SUB (p) != NO_NODE) {
14403       SOID_T x;
14404       make_soid (&x, STRONG, MODE (ROW_INT), 0);
14405       coerce_enclosed (SUB (NEXT_SUB (p)), &x);
14406     } else if (IS (p, DYNAMIC_REPLICATOR)) {
14407       SOID_T x;
14408       make_soid (&x, STRONG, MODE (INT), 0);
14409       coerce_enclosed (SUB (NEXT_SUB (p)), &x);
14410     }
14411   }
14412 }
14413 
14414 /**
14415 @brief Coerce unit.
14416 @param p Node in syntax tree.
14417 @param q Soid.
14418 **/
14419 
14420 static void
coerce_unit(NODE_T * p,SOID_T * q)14421 coerce_unit (NODE_T * p, SOID_T * q)
14422 {
14423   if (p == NO_NODE) {
14424     return;
14425   } else if (is_one_of (p, UNIT, TERTIARY, SECONDARY, PRIMARY, STOP)) {
14426     coerce_unit (SUB (p), q);
14427     MOID (p) = MOID (SUB (p));
14428 /* Ex primary */
14429   } else if (IS (p, CALL)) {
14430     coerce_call (SUB (p));
14431     INSERT_COERCIONS (p, MOID (p), q);
14432   } else if (IS (p, SLICE)) {
14433     coerce_slice (SUB (p));
14434     INSERT_COERCIONS (p, MOID (p), q);
14435   } else if (IS (p, CAST)) {
14436     coerce_cast (SUB (p));
14437     INSERT_COERCIONS (p, MOID (p), q);
14438   } else if (is_one_of (p, DENOTATION, IDENTIFIER, STOP)) {
14439     INSERT_COERCIONS (p, MOID (p), q);
14440   } else if (IS (p, FORMAT_TEXT)) {
14441     coerce_format_text (SUB (p));
14442     INSERT_COERCIONS (p, MOID (p), q);
14443   } else if (IS (p, ENCLOSED_CLAUSE)) {
14444     coerce_enclosed (p, q);
14445 /* Ex secondary */
14446   } else if (IS (p, SELECTION)) {
14447     coerce_selection (SUB (p));
14448     INSERT_COERCIONS (p, MOID (p), q);
14449   } else if (IS (p, GENERATOR)) {
14450     coerce_declarer (SUB (p));
14451     INSERT_COERCIONS (p, MOID (p), q);
14452 /* Ex tertiary */
14453   } else if (IS (p, NIHIL)) {
14454     if (ATTRIBUTE (MOID (q)) != REF_SYMBOL && MOID (q) != MODE (VOID)) {
14455       diagnostic_node (A68_ERROR, p, ERROR_NO_NAME_REQUIRED);
14456     }
14457     MOID (p) = depref_rows (MOID (p), MOID (q));
14458   } else if (IS (p, FORMULA)) {
14459     coerce_formula (SUB (p), q);
14460     INSERT_COERCIONS (p, MOID (p), q);
14461   } else if (IS (p, DIAGONAL_FUNCTION)) {
14462     coerce_diagonal (SUB (p));
14463     INSERT_COERCIONS (p, MOID (p), q);
14464   } else if (IS (p, TRANSPOSE_FUNCTION)) {
14465     coerce_transpose (SUB (p));
14466     INSERT_COERCIONS (p, MOID (p), q);
14467   } else if (IS (p, ROW_FUNCTION)) {
14468     coerce_row_column_function (SUB (p));
14469     INSERT_COERCIONS (p, MOID (p), q);
14470   } else if (IS (p, COLUMN_FUNCTION)) {
14471     coerce_row_column_function (SUB (p));
14472     INSERT_COERCIONS (p, MOID (p), q);
14473 /* Ex unit */
14474   } else if (IS (p, JUMP)) {
14475     if (MOID (q) == MODE (PROC_VOID)) {
14476       make_sub (p, p, PROCEDURING);
14477     }
14478     MOID (p) = depref_rows (MOID (p), MOID (q));
14479   } else if (IS (p, SKIP)) {
14480     MOID (p) = depref_rows (MOID (p), MOID (q));
14481   } else if (IS (p, ASSIGNATION)) {
14482     coerce_assignation (SUB (p));
14483     INSERT_COERCIONS (p, MOID (p), q);
14484     MOID (p) = depref_rows (MOID (p), MOID (q));
14485   } else if (IS (p, IDENTITY_RELATION)) {
14486     coerce_relation (SUB (p));
14487     INSERT_COERCIONS (p, MOID (p), q);
14488   } else if (IS (p, ROUTINE_TEXT)) {
14489     coerce_routine_text (SUB (p));
14490     INSERT_COERCIONS (p, MOID (p), q);
14491   } else if (is_one_of (p, AND_FUNCTION, OR_FUNCTION, STOP)) {
14492     coerce_bool_function (SUB (p));
14493     INSERT_COERCIONS (p, MOID (p), q);
14494   } else if (IS (p, ASSERTION)) {
14495     coerce_assertion (SUB (p));
14496     INSERT_COERCIONS (p, MOID (p), q);
14497   }
14498 }
14499 
14500 /**
14501 @brief Widen denotation depending on mode required, this is an extension to A68.
14502 @param p Node in syntax tree.
14503 **/
14504 
14505 void
widen_denotation(NODE_T * p)14506 widen_denotation (NODE_T * p)
14507 {
14508 #define WIDEN {\
14509   *q = *(SUB (q));\
14510   ATTRIBUTE (q) = DENOTATION;\
14511   MOID (q) = lm;\
14512   STATUS_SET (q, OPTIMAL_MASK);\
14513   }
14514 #define WARN_WIDENING\
14515   if (OPTION_PORTCHECK (&program) && !(STATUS_TEST (SUB (q), OPTIMAL_MASK))) {\
14516     diagnostic_node (A68_WARNING | A68_FORCE_DIAGNOSTICS, q, WARNING_WIDENING_NOT_PORTABLE);\
14517   }
14518   NODE_T *q;
14519   for (q = p; q != NO_NODE; FORWARD (q)) {
14520     widen_denotation (SUB (q));
14521     if (IS (q, WIDENING) && IS (SUB (q), DENOTATION)) {
14522       MOID_T *lm = MOID (q), *m = MOID (SUB (q));
14523       if (lm == MODE (LONGLONG_INT) && m == MODE (LONG_INT)) {
14524         WARN_WIDENING;
14525         WIDEN;
14526       }
14527       if (lm == MODE (LONG_INT) && m == MODE (INT)) {
14528         WARN_WIDENING;
14529         WIDEN;
14530       }
14531       if (lm == MODE (LONGLONG_REAL) && m == MODE (LONG_REAL)) {
14532         WARN_WIDENING;
14533         WIDEN;
14534       }
14535       if (lm == MODE (LONG_REAL) && m == MODE (REAL)) {
14536         WARN_WIDENING;
14537         WIDEN;
14538       }
14539       if (lm == MODE (LONG_REAL) && m == MODE (LONG_INT)) {
14540         WIDEN;
14541       }
14542       if (lm == MODE (REAL) && m == MODE (INT)) {
14543         WIDEN;
14544       }
14545       if (lm == MODE (LONGLONG_BITS) && m == MODE (LONG_BITS)) {
14546         WARN_WIDENING;
14547         WIDEN;
14548       }
14549       if (lm == MODE (LONG_BITS) && m == MODE (BITS)) {
14550         WARN_WIDENING;
14551         WIDEN;
14552       }
14553       return;
14554     }
14555   }
14556 #undef WIDEN
14557 #undef WARN_WIDENING
14558 }
14559 
14560 /********************************************************************/
14561 /* Static scope checker, at run time we check dynamic scope as well */
14562 /********************************************************************/
14563 
14564 /*
14565 Static scope checker.
14566 Also a little preparation for the monitor:
14567 - indicates UNITs that can be interrupted.
14568 */
14569 
14570 
14571 /**
14572 @brief Scope_make_tuple.
14573 @param e Level.
14574 @param t Whether transient.
14575 @return Tuple (e, t).
14576 **/
14577 
14578 static TUPLE_T
scope_make_tuple(int e,int t)14579 scope_make_tuple (int e, int t)
14580 {
14581   static TUPLE_T z;
14582   LEVEL (&z) = e;
14583   TRANSIENT (&z) = (BOOL_T) t;
14584   return (z);
14585 }
14586 
14587 /**
14588 @brief Link scope information into the list.
14589 @param sl Chain to link into.
14590 @param p Node in syntax tree.
14591 @param tup Tuple to link.
14592 **/
14593 
14594 static void
scope_add(SCOPE_T ** sl,NODE_T * p,TUPLE_T tup)14595 scope_add (SCOPE_T ** sl, NODE_T * p, TUPLE_T tup)
14596 {
14597   if (sl != NO_VAR) {
14598     SCOPE_T *ns = (SCOPE_T *) get_temp_heap_space ((unsigned) SIZE_AL (SCOPE_T));
14599     WHERE (ns) = p;
14600     TUPLE (ns) = tup;
14601     NEXT (ns) = *sl;
14602     *sl = ns;
14603   }
14604 }
14605 
14606 /**
14607 @brief Scope_check.
14608 @param top Top of scope chain.
14609 @param mask What to check.
14610 @param dest Level to check against.
14611 @return Whether errors were detected.
14612 **/
14613 
14614 static BOOL_T
scope_check(SCOPE_T * top,int mask,int dest)14615 scope_check (SCOPE_T * top, int mask, int dest)
14616 {
14617   SCOPE_T *s;
14618   int errors = 0;
14619 /* Transient names cannot be stored */
14620   if (mask & TRANSIENT) {
14621     for (s = top; s != NO_SCOPE; FORWARD (s)) {
14622       if (TRANSIENT (&TUPLE (s)) & TRANSIENT) {
14623         diagnostic_node (A68_ERROR, WHERE (s), ERROR_TRANSIENT_NAME);
14624         STATUS_SET (WHERE (s), SCOPE_ERROR_MASK);
14625         errors++;
14626       }
14627     }
14628   }
14629   for (s = top; s != NO_SCOPE; FORWARD (s)) {
14630     if (dest < LEVEL (&TUPLE (s)) && !STATUS_TEST (WHERE (s), SCOPE_ERROR_MASK)) {
14631 /* Potential scope violations */
14632       MOID_T *sw = MOID (WHERE (s));
14633       if (sw != NO_MOID) {
14634         if (IS (sw, REF_SYMBOL) || IS (sw, PROC_SYMBOL)
14635             || IS (sw, FORMAT_SYMBOL) || IS (sw, UNION_SYMBOL)) {
14636           diagnostic_node (A68_WARNING, WHERE (s), WARNING_SCOPE_STATIC, MOID (WHERE (s)), ATTRIBUTE (WHERE (s)));
14637         }
14638       }
14639       STATUS_SET (WHERE (s), SCOPE_ERROR_MASK);
14640       errors++;
14641     }
14642   }
14643   return ((BOOL_T) (errors == 0));
14644 }
14645 
14646 /**
14647 @brief Scope_check_multiple.
14648 @param top Top of scope chain.
14649 @param mask What to check.
14650 @param dest Level to check against.
14651 @return Whether error.
14652 **/
14653 
14654 static BOOL_T
scope_check_multiple(SCOPE_T * top,int mask,SCOPE_T * dest)14655 scope_check_multiple (SCOPE_T * top, int mask, SCOPE_T * dest)
14656 {
14657   BOOL_T no_err = A68_TRUE;
14658   for (; dest != NO_SCOPE; FORWARD (dest)) {
14659     no_err &= scope_check (top, mask, LEVEL (&TUPLE (dest)));
14660   }
14661   return (no_err);
14662 }
14663 
14664 /**
14665 @brief Check_identifier_usage.
14666 @param t Tag.
14667 @param p Node in syntax tree.
14668 **/
14669 
14670 static void
check_identifier_usage(TAG_T * t,NODE_T * p)14671 check_identifier_usage (TAG_T * t, NODE_T * p)
14672 {
14673   for (; p != NO_NODE; FORWARD (p)) {
14674     if (IS (p, IDENTIFIER) && TAX (p) == t && ATTRIBUTE (MOID (t)) != PROC_SYMBOL) {
14675       diagnostic_node (A68_WARNING, p, WARNING_UNINITIALISED);
14676     }
14677     check_identifier_usage (t, SUB (p));
14678   }
14679 }
14680 
14681 /**
14682 @brief Scope_find_youngest_outside.
14683 @param s Chain to link into.
14684 @param treshold Threshold level.
14685 @return Youngest tuple outside.
14686 **/
14687 
14688 static TUPLE_T
scope_find_youngest_outside(SCOPE_T * s,int treshold)14689 scope_find_youngest_outside (SCOPE_T * s, int treshold)
14690 {
14691   TUPLE_T z = scope_make_tuple (PRIMAL_SCOPE, NOT_TRANSIENT);
14692   for (; s != NO_SCOPE; FORWARD (s)) {
14693     if (LEVEL (&TUPLE (s)) > LEVEL (&z) && LEVEL (&TUPLE (s)) <= treshold) {
14694       z = TUPLE (s);
14695     }
14696   }
14697   return (z);
14698 }
14699 
14700 /**
14701 @brief Scope_find_youngest.
14702 @param s Chain to link into.
14703 @return Youngest tuple outside.
14704 **/
14705 
14706 static TUPLE_T
scope_find_youngest(SCOPE_T * s)14707 scope_find_youngest (SCOPE_T * s)
14708 {
14709   return (scope_find_youngest_outside (s, A68_MAX_INT));
14710 }
14711 
14712 /* Routines for determining scope of ROUTINE TEXT or FORMAT TEXT */
14713 
14714 /**
14715 @brief Get_declarer_elements.
14716 @param p Node in syntax tree.
14717 @param r Chain to link into.
14718 @param no_ref Whether no REF seen yet.
14719 **/
14720 
14721 static void
get_declarer_elements(NODE_T * p,SCOPE_T ** r,BOOL_T no_ref)14722 get_declarer_elements (NODE_T * p, SCOPE_T ** r, BOOL_T no_ref)
14723 {
14724   if (p != NO_NODE) {
14725     if (IS (p, BOUNDS)) {
14726       gather_scopes_for_youngest (SUB (p), r);
14727     } else if (IS (p, INDICANT)) {
14728       if (MOID (p) != NO_MOID && TAX (p) != NO_TAG && HAS_ROWS (MOID (p)) && no_ref) {
14729         scope_add (r, p, scope_make_tuple (TAG_LEX_LEVEL (TAX (p)), NOT_TRANSIENT));
14730       }
14731     } else if (IS (p, REF_SYMBOL)) {
14732       get_declarer_elements (NEXT (p), r, A68_FALSE);
14733     } else if (is_one_of (p, PROC_SYMBOL, UNION_SYMBOL, STOP)) {
14734       ;
14735     } else {
14736       get_declarer_elements (SUB (p), r, no_ref);
14737       get_declarer_elements (NEXT (p), r, no_ref);
14738     }
14739   }
14740 }
14741 
14742 /**
14743 @brief Gather_scopes_for_youngest.
14744 @param p Node in syntax tree.
14745 @param s Chain to link into.
14746 **/
14747 
14748 static void
gather_scopes_for_youngest(NODE_T * p,SCOPE_T ** s)14749 gather_scopes_for_youngest (NODE_T * p, SCOPE_T ** s)
14750 {
14751   for (; p != NO_NODE; FORWARD (p)) {
14752     if ((is_one_of (p, ROUTINE_TEXT, FORMAT_TEXT, STOP)) && (YOUNGEST_ENVIRON (TAX (p)) == PRIMAL_SCOPE)) {
14753       SCOPE_T *t = NO_SCOPE;
14754       TUPLE_T tup;
14755       gather_scopes_for_youngest (SUB (p), &t);
14756       tup = scope_find_youngest_outside (t, LEX_LEVEL (p));
14757       YOUNGEST_ENVIRON (TAX (p)) = LEVEL (&tup);
14758 /* Direct link into list iso "gather_scopes_for_youngest (SUB (p), s);" */
14759       if (t != NO_SCOPE) {
14760         SCOPE_T *u = t;
14761         while (NEXT (u) != NO_SCOPE) {
14762           FORWARD (u);
14763         }
14764         NEXT (u) = *s;
14765         (*s) = t;
14766       }
14767     } else if (is_one_of (p, IDENTIFIER, OPERATOR, STOP)) {
14768       if (TAX (p) != NO_TAG && TAG_LEX_LEVEL (TAX (p)) != PRIMAL_SCOPE) {
14769         scope_add (s, p, scope_make_tuple (TAG_LEX_LEVEL (TAX (p)), NOT_TRANSIENT));
14770       }
14771     } else if (IS (p, DECLARER)) {
14772       get_declarer_elements (p, s, A68_TRUE);
14773     } else {
14774       gather_scopes_for_youngest (SUB (p), s);
14775     }
14776   }
14777 }
14778 
14779 /**
14780 @brief Get_youngest_environs.
14781 @param p Node in syntax tree.
14782 **/
14783 
14784 static void
get_youngest_environs(NODE_T * p)14785 get_youngest_environs (NODE_T * p)
14786 {
14787   for (; p != NO_NODE; FORWARD (p)) {
14788     if (is_one_of (p, ROUTINE_TEXT, FORMAT_TEXT, STOP)) {
14789       SCOPE_T *s = NO_SCOPE;
14790       TUPLE_T tup;
14791       gather_scopes_for_youngest (SUB (p), &s);
14792       tup = scope_find_youngest_outside (s, LEX_LEVEL (p));
14793       YOUNGEST_ENVIRON (TAX (p)) = LEVEL (&tup);
14794     } else {
14795       get_youngest_environs (SUB (p));
14796     }
14797   }
14798 }
14799 
14800 /**
14801 @brief Bind_scope_to_tag.
14802 @param p Node in syntax tree.
14803 **/
14804 
14805 static void
bind_scope_to_tag(NODE_T * p)14806 bind_scope_to_tag (NODE_T * p)
14807 {
14808   for (; p != NO_NODE; FORWARD (p)) {
14809     if (IS (p, DEFINING_IDENTIFIER) && MOID (p) == MODE (FORMAT)) {
14810       if (IS (NEXT_NEXT (p), FORMAT_TEXT)) {
14811         SCOPE (TAX (p)) = YOUNGEST_ENVIRON (TAX (NEXT_NEXT (p)));
14812         SCOPE_ASSIGNED (TAX (p)) = A68_TRUE;
14813       }
14814       return;
14815     } else if (IS (p, DEFINING_IDENTIFIER)) {
14816       if (IS (NEXT_NEXT (p), ROUTINE_TEXT)) {
14817         SCOPE (TAX (p)) = YOUNGEST_ENVIRON (TAX (NEXT_NEXT (p)));
14818         SCOPE_ASSIGNED (TAX (p)) = A68_TRUE;
14819       }
14820       return;
14821     } else {
14822       bind_scope_to_tag (SUB (p));
14823     }
14824   }
14825 }
14826 
14827 /**
14828 @brief Bind_scope_to_tags.
14829 @param p Node in syntax tree.
14830 **/
14831 
14832 static void
bind_scope_to_tags(NODE_T * p)14833 bind_scope_to_tags (NODE_T * p)
14834 {
14835   for (; p != NO_NODE; FORWARD (p)) {
14836     if (is_one_of (p, PROCEDURE_DECLARATION, IDENTITY_DECLARATION, STOP)) {
14837       bind_scope_to_tag (SUB (p));
14838     } else {
14839       bind_scope_to_tags (SUB (p));
14840     }
14841   }
14842 }
14843 
14844 /**
14845 @brief Scope_bounds.
14846 @param p Node in syntax tree.
14847 **/
14848 
14849 static void
scope_bounds(NODE_T * p)14850 scope_bounds (NODE_T * p)
14851 {
14852   for (; p != NO_NODE; FORWARD (p)) {
14853     if (IS (p, UNIT)) {
14854       scope_statement (p, NO_VAR);
14855     } else {
14856       scope_bounds (SUB (p));
14857     }
14858   }
14859 }
14860 
14861 /**
14862 @brief Scope_declarer.
14863 @param p Node in syntax tree.
14864 **/
14865 
14866 static void
scope_declarer(NODE_T * p)14867 scope_declarer (NODE_T * p)
14868 {
14869   if (p != NO_NODE) {
14870     if (IS (p, BOUNDS)) {
14871       scope_bounds (SUB (p));
14872     } else if (IS (p, INDICANT)) {
14873       ;
14874     } else if (IS (p, REF_SYMBOL)) {
14875       scope_declarer (NEXT (p));
14876     } else if (is_one_of (p, PROC_SYMBOL, UNION_SYMBOL, STOP)) {
14877       ;
14878     } else {
14879       scope_declarer (SUB (p));
14880       scope_declarer (NEXT (p));
14881     }
14882   }
14883 }
14884 
14885 /**
14886 @brief Scope_identity_declaration.
14887 @param p Node in syntax tree.
14888 **/
14889 
14890 static void
scope_identity_declaration(NODE_T * p)14891 scope_identity_declaration (NODE_T * p)
14892 {
14893   for (; p != NO_NODE; FORWARD (p)) {
14894     scope_identity_declaration (SUB (p));
14895     if (IS (p, DEFINING_IDENTIFIER)) {
14896       NODE_T *unit = NEXT_NEXT (p);
14897       SCOPE_T *s = NO_SCOPE;
14898       TUPLE_T tup;
14899       int z = PRIMAL_SCOPE;
14900       if (ATTRIBUTE (MOID (TAX (p))) != PROC_SYMBOL) {
14901         check_identifier_usage (TAX (p), unit);
14902       }
14903       scope_statement (unit, &s);
14904       (void) scope_check (s, TRANSIENT, LEX_LEVEL (p));
14905       tup = scope_find_youngest (s);
14906       z = LEVEL (&tup);
14907       if (z < LEX_LEVEL (p)) {
14908         SCOPE (TAX (p)) = z;
14909         SCOPE_ASSIGNED (TAX (p)) = A68_TRUE;
14910       }
14911       STATUS_SET (unit, INTERRUPTIBLE_MASK);
14912       return;
14913     }
14914   }
14915 }
14916 
14917 /**
14918 @brief Scope_variable_declaration.
14919 @param p Node in syntax tree.
14920 **/
14921 
14922 static void
scope_variable_declaration(NODE_T * p)14923 scope_variable_declaration (NODE_T * p)
14924 {
14925   for (; p != NO_NODE; FORWARD (p)) {
14926     scope_variable_declaration (SUB (p));
14927     if (IS (p, DECLARER)) {
14928       scope_declarer (SUB (p));
14929     } else if (IS (p, DEFINING_IDENTIFIER)) {
14930       if (whether (p, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, UNIT, STOP)) {
14931         NODE_T *unit = NEXT_NEXT (p);
14932         SCOPE_T *s = NO_SCOPE;
14933         check_identifier_usage (TAX (p), unit);
14934         scope_statement (unit, &s);
14935         (void) scope_check (s, TRANSIENT, LEX_LEVEL (p));
14936         STATUS_SET (unit, INTERRUPTIBLE_MASK);
14937         return;
14938       }
14939     }
14940   }
14941 }
14942 
14943 /**
14944 @brief Scope_procedure_declaration.
14945 @param p Node in syntax tree.
14946 **/
14947 
14948 static void
scope_procedure_declaration(NODE_T * p)14949 scope_procedure_declaration (NODE_T * p)
14950 {
14951   for (; p != NO_NODE; FORWARD (p)) {
14952     scope_procedure_declaration (SUB (p));
14953     if (is_one_of (p, DEFINING_IDENTIFIER, DEFINING_OPERATOR, STOP)) {
14954       NODE_T *unit = NEXT_NEXT (p);
14955       SCOPE_T *s = NO_SCOPE;
14956       scope_statement (unit, &s);
14957       (void) scope_check (s, NOT_TRANSIENT, LEX_LEVEL (p));
14958       STATUS_SET (unit, INTERRUPTIBLE_MASK);
14959       return;
14960     }
14961   }
14962 }
14963 
14964 /**
14965 @brief Scope_declaration_list.
14966 @param p Node in syntax tree.
14967 **/
14968 
14969 static void
scope_declaration_list(NODE_T * p)14970 scope_declaration_list (NODE_T * p)
14971 {
14972   if (p != NO_NODE) {
14973     if (IS (p, IDENTITY_DECLARATION)) {
14974       scope_identity_declaration (SUB (p));
14975     } else if (IS (p, VARIABLE_DECLARATION)) {
14976       scope_variable_declaration (SUB (p));
14977     } else if (IS (p, MODE_DECLARATION)) {
14978       scope_declarer (SUB (p));
14979     } else if (IS (p, PRIORITY_DECLARATION)) {
14980       ;
14981     } else if (IS (p, PROCEDURE_DECLARATION)) {
14982       scope_procedure_declaration (SUB (p));
14983     } else if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
14984       scope_procedure_declaration (SUB (p));
14985     } else if (is_one_of (p, BRIEF_OPERATOR_DECLARATION, OPERATOR_DECLARATION, STOP)) {
14986       scope_procedure_declaration (SUB (p));
14987     } else {
14988       scope_declaration_list (SUB (p));
14989       scope_declaration_list (NEXT (p));
14990     }
14991   }
14992 }
14993 
14994 /**
14995 @brief Scope_arguments.
14996 @param p Node in syntax tree.
14997 **/
14998 
14999 static void
scope_arguments(NODE_T * p)15000 scope_arguments (NODE_T * p)
15001 {
15002   for (; p != NO_NODE; FORWARD (p)) {
15003     if (IS (p, UNIT)) {
15004       SCOPE_T *s = NO_SCOPE;
15005       scope_statement (p, &s);
15006       (void) scope_check (s, TRANSIENT, LEX_LEVEL (p));
15007     } else {
15008       scope_arguments (SUB (p));
15009     }
15010   }
15011 }
15012 
15013 /**
15014 @brief Is_coercion.
15015 @param p Node in syntax tree.
15016 **/
15017 
15018 BOOL_T
is_coercion(NODE_T * p)15019 is_coercion (NODE_T * p)
15020 {
15021   if (p != NO_NODE) {
15022     switch (ATTRIBUTE (p)) {
15023     case DEPROCEDURING:
15024     case DEREFERENCING:
15025     case UNITING:
15026     case ROWING:
15027     case WIDENING:
15028     case VOIDING:
15029     case PROCEDURING:
15030       {
15031         return (A68_TRUE);
15032       }
15033     default:
15034       {
15035         return (A68_FALSE);
15036       }
15037     }
15038   } else {
15039     return (A68_FALSE);
15040   }
15041 }
15042 
15043 /**
15044 @brief Scope_coercion.
15045 @param p Node in syntax tree.
15046 @param s Chain to link into.
15047 **/
15048 
15049 static void
scope_coercion(NODE_T * p,SCOPE_T ** s)15050 scope_coercion (NODE_T * p, SCOPE_T ** s)
15051 {
15052   if (is_coercion (p)) {
15053     if (IS (p, VOIDING)) {
15054       scope_coercion (SUB (p), NO_VAR);
15055     } else if (IS (p, DEREFERENCING)) {
15056 /* Leave this to the dynamic scope checker */
15057       scope_coercion (SUB (p), NO_VAR);
15058     } else if (IS (p, DEPROCEDURING)) {
15059       scope_coercion (SUB (p), NO_VAR);
15060     } else if (IS (p, ROWING)) {
15061       SCOPE_T *z = NO_SCOPE;
15062       scope_coercion (SUB (p), &z);
15063       (void) scope_check (z, TRANSIENT, LEX_LEVEL (p));
15064       if (IS_REF_FLEX (MOID (SUB (p)))) {
15065         scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), TRANSIENT));
15066       } else {
15067         scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), NOT_TRANSIENT));
15068       }
15069     } else if (IS (p, PROCEDURING)) {
15070 /* Can only be a JUMP */
15071       NODE_T *q = SUB_SUB (p);
15072       if (IS (q, GOTO_SYMBOL)) {
15073         FORWARD (q);
15074       }
15075       scope_add (s, q, scope_make_tuple (TAG_LEX_LEVEL (TAX (q)), NOT_TRANSIENT));
15076     } else if (IS (p, UNITING)) {
15077       SCOPE_T *z = NO_SCOPE;
15078       scope_coercion (SUB (p), &z);
15079       (void) scope_check (z, TRANSIENT, LEX_LEVEL (p));
15080       scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), NOT_TRANSIENT));
15081     } else {
15082       scope_coercion (SUB (p), s);
15083     }
15084   } else {
15085     scope_statement (p, s);
15086   }
15087 }
15088 
15089 /**
15090 @brief Scope_format_text.
15091 @param p Node in syntax tree.
15092 @param s Chain to link into.
15093 **/
15094 
15095 static void
scope_format_text(NODE_T * p,SCOPE_T ** s)15096 scope_format_text (NODE_T * p, SCOPE_T ** s)
15097 {
15098   for (; p != NO_NODE; FORWARD (p)) {
15099     if (IS (p, FORMAT_PATTERN)) {
15100       scope_enclosed_clause (SUB (NEXT_SUB (p)), s);
15101     } else if (IS (p, FORMAT_ITEM_G) && NEXT (p) != NO_NODE) {
15102       scope_enclosed_clause (SUB_NEXT (p), s);
15103     } else if (IS (p, DYNAMIC_REPLICATOR)) {
15104       scope_enclosed_clause (SUB (NEXT_SUB (p)), s);
15105     } else {
15106       scope_format_text (SUB (p), s);
15107     }
15108   }
15109 }
15110 
15111 /**
15112 @brief Scope_operand.
15113 @param p Node in syntax tree.
15114 @param s Chain to link into.
15115 **/
15116 
15117 static void
scope_operand(NODE_T * p,SCOPE_T ** s)15118 scope_operand (NODE_T * p, SCOPE_T ** s)
15119 {
15120   if (IS (p, MONADIC_FORMULA)) {
15121     scope_operand (NEXT_SUB (p), s);
15122   } else if (IS (p, FORMULA)) {
15123     scope_formula (p, s);
15124   } else if (IS (p, SECONDARY)) {
15125     scope_statement (SUB (p), s);
15126   }
15127 }
15128 
15129 /**
15130 @brief Scope_formula.
15131 @param p Node in syntax tree.
15132 @param s Chain to link into.
15133 **/
15134 
15135 static void
scope_formula(NODE_T * p,SCOPE_T ** s)15136 scope_formula (NODE_T * p, SCOPE_T ** s)
15137 {
15138   NODE_T *q = SUB (p);
15139   SCOPE_T *s2 = NO_SCOPE;
15140   scope_operand (q, &s2);
15141   (void) scope_check (s2, TRANSIENT, LEX_LEVEL (p));
15142   if (NEXT (q) != NO_NODE) {
15143     SCOPE_T *s3 = NO_SCOPE;
15144     scope_operand (NEXT_NEXT (q), &s3);
15145     (void) scope_check (s3, TRANSIENT, LEX_LEVEL (p));
15146   }
15147   (void) s;
15148 }
15149 
15150 /**
15151 @brief Scope_routine_text.
15152 @param p Node in syntax tree.
15153 @param s Chain to link into.
15154 **/
15155 
15156 static void
scope_routine_text(NODE_T * p,SCOPE_T ** s)15157 scope_routine_text (NODE_T * p, SCOPE_T ** s)
15158 {
15159   NODE_T *q = SUB (p), *routine = (IS (q, PARAMETER_PACK) ? NEXT (q) : q);
15160   SCOPE_T *x = NO_SCOPE;
15161   TUPLE_T routine_tuple;
15162   scope_statement (NEXT_NEXT (routine), &x);
15163   (void) scope_check (x, TRANSIENT, LEX_LEVEL (p));
15164   routine_tuple = scope_make_tuple (YOUNGEST_ENVIRON (TAX (p)), NOT_TRANSIENT);
15165   scope_add (s, p, routine_tuple);
15166 }
15167 
15168 /**
15169 @brief Scope_statement.
15170 @param p Node in syntax tree.
15171 @param s Chain to link into.
15172 **/
15173 
15174 static void
scope_statement(NODE_T * p,SCOPE_T ** s)15175 scope_statement (NODE_T * p, SCOPE_T ** s)
15176 {
15177   if (is_coercion (p)) {
15178     scope_coercion (p, s);
15179   } else if (is_one_of (p, PRIMARY, SECONDARY, TERTIARY, UNIT, STOP)) {
15180     scope_statement (SUB (p), s);
15181   } else if (is_one_of (p, DENOTATION, NIHIL, STOP)) {
15182     scope_add (s, p, scope_make_tuple (PRIMAL_SCOPE, NOT_TRANSIENT));
15183   } else if (IS (p, IDENTIFIER)) {
15184     if (IS (MOID (p), REF_SYMBOL)) {
15185       if (PRIO (TAX (p)) == PARAMETER_IDENTIFIER) {
15186         scope_add (s, p, scope_make_tuple (TAG_LEX_LEVEL (TAX (p)) - 1, NOT_TRANSIENT));
15187       } else {
15188         if (HEAP (TAX (p)) == HEAP_SYMBOL) {
15189           scope_add (s, p, scope_make_tuple (PRIMAL_SCOPE, NOT_TRANSIENT));
15190         } else if (SCOPE_ASSIGNED (TAX (p))) {
15191           scope_add (s, p, scope_make_tuple (SCOPE (TAX (p)), NOT_TRANSIENT));
15192         } else {
15193           scope_add (s, p, scope_make_tuple (TAG_LEX_LEVEL (TAX (p)), NOT_TRANSIENT));
15194         }
15195       }
15196     } else if (ATTRIBUTE (MOID (p)) == PROC_SYMBOL && SCOPE_ASSIGNED (TAX (p)) == A68_TRUE) {
15197       scope_add (s, p, scope_make_tuple (SCOPE (TAX (p)), NOT_TRANSIENT));
15198     } else if (MOID (p) == MODE (FORMAT) && SCOPE_ASSIGNED (TAX (p)) == A68_TRUE) {
15199       scope_add (s, p, scope_make_tuple (SCOPE (TAX (p)), NOT_TRANSIENT));
15200     }
15201   } else if (IS (p, ENCLOSED_CLAUSE)) {
15202     scope_enclosed_clause (SUB (p), s);
15203   } else if (IS (p, CALL)) {
15204     SCOPE_T *x = NO_SCOPE;
15205     scope_statement (SUB (p), &x);
15206     (void) scope_check (x, NOT_TRANSIENT, LEX_LEVEL (p));
15207     scope_arguments (NEXT_SUB (p));
15208   } else if (IS (p, SLICE)) {
15209     SCOPE_T *x = NO_SCOPE;
15210     MOID_T *m = MOID (SUB (p));
15211     if (IS (m, REF_SYMBOL)) {
15212       if (ATTRIBUTE (SUB (p)) == PRIMARY && ATTRIBUTE (SUB_SUB (p)) == SLICE) {
15213         scope_statement (SUB (p), s);
15214       } else {
15215         scope_statement (SUB (p), &x);
15216         (void) scope_check (x, NOT_TRANSIENT, LEX_LEVEL (p));
15217       }
15218       if (IS (SUB (m), FLEX_SYMBOL)) {
15219         scope_add (s, SUB (p), scope_make_tuple (LEX_LEVEL (p), TRANSIENT));
15220       }
15221       scope_bounds (SUB (NEXT_SUB (p)));
15222     }
15223     if (IS (MOID (p), REF_SYMBOL)) {
15224       scope_add (s, p, scope_find_youngest (x));
15225     }
15226   } else if (IS (p, FORMAT_TEXT)) {
15227     SCOPE_T *x = NO_SCOPE;
15228     scope_format_text (SUB (p), &x);
15229     scope_add (s, p, scope_find_youngest (x));
15230   } else if (IS (p, CAST)) {
15231     SCOPE_T *x = NO_SCOPE;
15232     scope_enclosed_clause (SUB (NEXT_SUB (p)), &x);
15233     (void) scope_check (x, NOT_TRANSIENT, LEX_LEVEL (p));
15234     scope_add (s, p, scope_find_youngest (x));
15235   } else if (IS (p, SELECTION)) {
15236     SCOPE_T *ns = NO_SCOPE;
15237     scope_statement (NEXT_SUB (p), &ns);
15238     (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (p));
15239     if (is_ref_refety_flex (MOID (NEXT_SUB (p)))) {
15240       scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), TRANSIENT));
15241     }
15242     scope_add (s, p, scope_find_youngest (ns));
15243   } else if (IS (p, GENERATOR)) {
15244     if (IS (SUB (p), LOC_SYMBOL)) {
15245       if (NON_LOCAL (p) != NO_TABLE) {
15246         scope_add (s, p, scope_make_tuple (LEVEL (NON_LOCAL (p)), NOT_TRANSIENT));
15247       } else {
15248         scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), NOT_TRANSIENT));
15249       }
15250     } else {
15251       scope_add (s, p, scope_make_tuple (PRIMAL_SCOPE, NOT_TRANSIENT));
15252     }
15253     scope_declarer (SUB (NEXT_SUB (p)));
15254   } else if (IS (p, DIAGONAL_FUNCTION)) {
15255     NODE_T *q = SUB (p);
15256     SCOPE_T *ns = NO_SCOPE;
15257     if (IS (q, TERTIARY)) {
15258       scope_statement (SUB (q), &ns);
15259       (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
15260       ns = NO_SCOPE;
15261       FORWARD (q);
15262     }
15263     scope_statement (SUB_NEXT (q), &ns);
15264     (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
15265     scope_add (s, p, scope_find_youngest (ns));
15266   } else if (IS (p, TRANSPOSE_FUNCTION)) {
15267     NODE_T *q = SUB (p);
15268     SCOPE_T *ns = NO_SCOPE;
15269     scope_statement (SUB_NEXT (q), &ns);
15270     (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
15271     scope_add (s, p, scope_find_youngest (ns));
15272   } else if (IS (p, ROW_FUNCTION)) {
15273     NODE_T *q = SUB (p);
15274     SCOPE_T *ns = NO_SCOPE;
15275     if (IS (q, TERTIARY)) {
15276       scope_statement (SUB (q), &ns);
15277       (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
15278       ns = NO_SCOPE;
15279       FORWARD (q);
15280     }
15281     scope_statement (SUB_NEXT (q), &ns);
15282     (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
15283     scope_add (s, p, scope_find_youngest (ns));
15284   } else if (IS (p, COLUMN_FUNCTION)) {
15285     NODE_T *q = SUB (p);
15286     SCOPE_T *ns = NO_SCOPE;
15287     if (IS (q, TERTIARY)) {
15288       scope_statement (SUB (q), &ns);
15289       (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
15290       ns = NO_SCOPE;
15291       FORWARD (q);
15292     }
15293     scope_statement (SUB_NEXT (q), &ns);
15294     (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
15295     scope_add (s, p, scope_find_youngest (ns));
15296   } else if (IS (p, FORMULA)) {
15297     scope_formula (p, s);
15298   } else if (IS (p, ASSIGNATION)) {
15299     NODE_T *unit = NEXT (NEXT_SUB (p));
15300     SCOPE_T *ns = NO_SCOPE, *nd = NO_SCOPE;
15301     TUPLE_T tup;
15302     scope_statement (SUB_SUB (p), &nd);
15303     scope_statement (unit, &ns);
15304     (void) scope_check_multiple (ns, TRANSIENT, nd);
15305     tup = scope_find_youngest (nd);
15306     scope_add (s, p, scope_make_tuple (LEVEL (&tup), NOT_TRANSIENT));
15307   } else if (IS (p, ROUTINE_TEXT)) {
15308     scope_routine_text (p, s);
15309   } else if (is_one_of (p, IDENTITY_RELATION, AND_FUNCTION, OR_FUNCTION, STOP)) {
15310     SCOPE_T *n = NO_SCOPE;
15311     scope_statement (SUB (p), &n);
15312     scope_statement (NEXT (NEXT_SUB (p)), &n);
15313     (void) scope_check (n, NOT_TRANSIENT, LEX_LEVEL (p));
15314   } else if (IS (p, ASSERTION)) {
15315     SCOPE_T *n = NO_SCOPE;
15316     scope_enclosed_clause (SUB (NEXT_SUB (p)), &n);
15317     (void) scope_check (n, NOT_TRANSIENT, LEX_LEVEL (p));
15318   } else if (is_one_of (p, JUMP, SKIP, STOP)) {
15319     ;
15320   }
15321 }
15322 
15323 /**
15324 @brief Scope_statement_list.
15325 @param p Node in syntax tree.
15326 @param s Chain to link into.
15327 **/
15328 
15329 static void
scope_statement_list(NODE_T * p,SCOPE_T ** s)15330 scope_statement_list (NODE_T * p, SCOPE_T ** s)
15331 {
15332   for (; p != NO_NODE; FORWARD (p)) {
15333     if (IS (p, UNIT)) {
15334       STATUS_SET (p, INTERRUPTIBLE_MASK);
15335       scope_statement (p, s);
15336     } else {
15337       scope_statement_list (SUB (p), s);
15338     }
15339   }
15340 }
15341 
15342 /**
15343 @brief Scope_serial_clause.
15344 @param p Node in syntax tree.
15345 @param s Chain to link into.
15346 @param terminator Whether unit terminates clause.
15347 **/
15348 
15349 static void
scope_serial_clause(NODE_T * p,SCOPE_T ** s,BOOL_T terminator)15350 scope_serial_clause (NODE_T * p, SCOPE_T ** s, BOOL_T terminator)
15351 {
15352   if (p != NO_NODE) {
15353     if (IS (p, INITIALISER_SERIES)) {
15354       scope_serial_clause (SUB (p), s, A68_FALSE);
15355       scope_serial_clause (NEXT (p), s, terminator);
15356     } else if (IS (p, DECLARATION_LIST)) {
15357       scope_declaration_list (SUB (p));
15358     } else if (is_one_of (p, LABEL, SEMI_SYMBOL, EXIT_SYMBOL, STOP)) {
15359       scope_serial_clause (NEXT (p), s, terminator);
15360     } else if (is_one_of (p, SERIAL_CLAUSE, ENQUIRY_CLAUSE, STOP)) {
15361       if (NEXT (p) != NO_NODE) {
15362         int j = ATTRIBUTE (NEXT (p));
15363         if (j == EXIT_SYMBOL || j == END_SYMBOL || j == CLOSE_SYMBOL) {
15364           scope_serial_clause (SUB (p), s, A68_TRUE);
15365         } else {
15366           scope_serial_clause (SUB (p), s, A68_FALSE);
15367         }
15368       } else {
15369         scope_serial_clause (SUB (p), s, A68_TRUE);
15370       }
15371       scope_serial_clause (NEXT (p), s, terminator);
15372     } else if (IS (p, LABELED_UNIT)) {
15373       scope_serial_clause (SUB (p), s, terminator);
15374     } else if (IS (p, UNIT)) {
15375       STATUS_SET (p, INTERRUPTIBLE_MASK);
15376       if (terminator) {
15377         scope_statement (p, s);
15378       } else {
15379         scope_statement (p, NO_VAR);
15380       }
15381     }
15382   }
15383 }
15384 
15385 /**
15386 @brief Scope_closed_clause.
15387 @param p Node in syntax tree.
15388 @param s Chain to link into.
15389 **/
15390 
15391 static void
scope_closed_clause(NODE_T * p,SCOPE_T ** s)15392 scope_closed_clause (NODE_T * p, SCOPE_T ** s)
15393 {
15394   if (p != NO_NODE) {
15395     if (IS (p, SERIAL_CLAUSE)) {
15396       scope_serial_clause (p, s, A68_TRUE);
15397     } else if (is_one_of (p, OPEN_SYMBOL, BEGIN_SYMBOL, STOP)) {
15398       scope_closed_clause (NEXT (p), s);
15399     }
15400   }
15401 }
15402 
15403 /**
15404 @brief Scope_collateral_clause.
15405 @param p Node in syntax tree.
15406 @param s Chain to link into.
15407 **/
15408 
15409 static void
scope_collateral_clause(NODE_T * p,SCOPE_T ** s)15410 scope_collateral_clause (NODE_T * p, SCOPE_T ** s)
15411 {
15412   if (p != NO_NODE) {
15413     if (!(whether (p, BEGIN_SYMBOL, END_SYMBOL, STOP) || whether (p, OPEN_SYMBOL, CLOSE_SYMBOL, STOP))) {
15414       scope_statement_list (p, s);
15415     }
15416   }
15417 }
15418 
15419 /**
15420 @brief Scope_conditional_clause.
15421 @param p Node in syntax tree.
15422 @param s Chain to link into.
15423 **/
15424 
15425 static void
scope_conditional_clause(NODE_T * p,SCOPE_T ** s)15426 scope_conditional_clause (NODE_T * p, SCOPE_T ** s)
15427 {
15428   scope_serial_clause (NEXT_SUB (p), NO_VAR, A68_TRUE);
15429   FORWARD (p);
15430   scope_serial_clause (NEXT_SUB (p), s, A68_TRUE);
15431   if ((FORWARD (p)) != NO_NODE) {
15432     if (is_one_of (p, ELSE_PART, CHOICE, STOP)) {
15433       scope_serial_clause (NEXT_SUB (p), s, A68_TRUE);
15434     } else if (is_one_of (p, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
15435       scope_conditional_clause (SUB (p), s);
15436     }
15437   }
15438 }
15439 
15440 /**
15441 @brief Scope_case_clause.
15442 @param p Node in syntax tree.
15443 @param s Chain to link into.
15444 **/
15445 
15446 static void
scope_case_clause(NODE_T * p,SCOPE_T ** s)15447 scope_case_clause (NODE_T * p, SCOPE_T ** s)
15448 {
15449   SCOPE_T *n = NO_SCOPE;
15450   scope_serial_clause (NEXT_SUB (p), &n, A68_TRUE);
15451   (void) scope_check (n, NOT_TRANSIENT, LEX_LEVEL (p));
15452   FORWARD (p);
15453   scope_statement_list (NEXT_SUB (p), s);
15454   if ((FORWARD (p)) != NO_NODE) {
15455     if (is_one_of (p, OUT_PART, CHOICE, STOP)) {
15456       scope_serial_clause (NEXT_SUB (p), s, A68_TRUE);
15457     } else if (is_one_of (p, CASE_OUSE_PART, BRIEF_OUSE_PART, STOP)) {
15458       scope_case_clause (SUB (p), s);
15459     } else if (is_one_of (p, CONFORMITY_OUSE_PART, BRIEF_CONFORMITY_OUSE_PART, STOP)) {
15460       scope_case_clause (SUB (p), s);
15461     }
15462   }
15463 }
15464 
15465 /**
15466 @brief Scope_loop_clause.
15467 @param p Node in syntax tree.
15468 **/
15469 
15470 static void
scope_loop_clause(NODE_T * p)15471 scope_loop_clause (NODE_T * p)
15472 {
15473   if (p != NO_NODE) {
15474     if (IS (p, FOR_PART)) {
15475       scope_loop_clause (NEXT (p));
15476     } else if (is_one_of (p, FROM_PART, BY_PART, TO_PART, STOP)) {
15477       scope_statement (NEXT_SUB (p), NO_VAR);
15478       scope_loop_clause (NEXT (p));
15479     } else if (IS (p, WHILE_PART)) {
15480       scope_serial_clause (NEXT_SUB (p), NO_VAR, A68_TRUE);
15481       scope_loop_clause (NEXT (p));
15482     } else if (is_one_of (p, DO_PART, ALT_DO_PART, STOP)) {
15483       NODE_T *do_p = NEXT_SUB (p), *un_p;
15484       if (IS (do_p, SERIAL_CLAUSE)) {
15485         scope_serial_clause (do_p, NO_VAR, A68_TRUE);
15486         un_p = NEXT (do_p);
15487       } else {
15488         un_p = do_p;
15489       }
15490       if (un_p != NO_NODE && IS (un_p, UNTIL_PART)) {
15491         scope_serial_clause (NEXT_SUB (un_p), NO_VAR, A68_TRUE);
15492       }
15493     }
15494   }
15495 }
15496 
15497 /**
15498 @brief Scope_enclosed_clause.
15499 @param p Node in syntax tree.
15500 @param s Chain to link into.
15501 **/
15502 
15503 static void
scope_enclosed_clause(NODE_T * p,SCOPE_T ** s)15504 scope_enclosed_clause (NODE_T * p, SCOPE_T ** s)
15505 {
15506   if (IS (p, ENCLOSED_CLAUSE)) {
15507     scope_enclosed_clause (SUB (p), s);
15508   } else if (IS (p, CLOSED_CLAUSE)) {
15509     scope_closed_clause (SUB (p), s);
15510   } else if (is_one_of (p, COLLATERAL_CLAUSE, PARALLEL_CLAUSE, STOP)) {
15511     scope_collateral_clause (SUB (p), s);
15512   } else if (IS (p, CONDITIONAL_CLAUSE)) {
15513     scope_conditional_clause (SUB (p), s);
15514   } else if (is_one_of (p, CASE_CLAUSE, CONFORMITY_CLAUSE, STOP)) {
15515     scope_case_clause (SUB (p), s);
15516   } else if (IS (p, LOOP_CLAUSE)) {
15517     scope_loop_clause (SUB (p));
15518   }
15519 }
15520 
15521 /**
15522 @brief Whether a symbol table contains no (anonymous) definition.
15523 @param t Symbol table.
15524 \return TRUE or FALSE
15525 **/
15526 
15527 static BOOL_T
empty_table(TABLE_T * t)15528 empty_table (TABLE_T * t)
15529 {
15530   if (IDENTIFIERS (t) == NO_TAG) {
15531     return ((BOOL_T) (OPERATORS (t) == NO_TAG && INDICANTS (t) == NO_TAG));
15532   } else if (PRIO (IDENTIFIERS (t)) == LOOP_IDENTIFIER && NEXT (IDENTIFIERS (t)) == NO_TAG) {
15533     return ((BOOL_T) (OPERATORS (t) == NO_TAG && INDICANTS (t) == NO_TAG));
15534   } else if (PRIO (IDENTIFIERS (t)) == SPECIFIER_IDENTIFIER && NEXT (IDENTIFIERS (t)) == NO_TAG) {
15535     return ((BOOL_T) (OPERATORS (t) == NO_TAG && INDICANTS (t) == NO_TAG));
15536   } else {
15537     return (A68_FALSE);
15538   }
15539 }
15540 
15541 /**
15542 @brief Indicate non-local environs.
15543 @param p Node in syntax tree.
15544 @param max Lex level threshold.
15545 **/
15546 
15547 static void
get_non_local_environs(NODE_T * p,int max)15548 get_non_local_environs (NODE_T * p, int max)
15549 {
15550   for (; p != NO_NODE; FORWARD (p)) {
15551     if (IS (p, ROUTINE_TEXT)) {
15552       get_non_local_environs (SUB (p), LEX_LEVEL (SUB (p)));
15553     } else if (IS (p, FORMAT_TEXT)) {
15554       get_non_local_environs (SUB (p), LEX_LEVEL (SUB (p)));
15555     } else {
15556       get_non_local_environs (SUB (p), max);
15557       NON_LOCAL (p) = NO_TABLE;
15558       if (TABLE (p) != NO_TABLE) {
15559         TABLE_T *q = TABLE (p);
15560         while (q != NO_TABLE && empty_table (q)
15561                && PREVIOUS (q) != NO_TABLE && LEVEL (PREVIOUS (q)) >= max) {
15562           NON_LOCAL (p) = PREVIOUS (q);
15563           q = PREVIOUS (q);
15564         }
15565       }
15566     }
15567   }
15568 }
15569 
15570 /**
15571 @brief Scope_checker.
15572 @param p Node in syntax tree.
15573 **/
15574 
15575 void
scope_checker(NODE_T * p)15576 scope_checker (NODE_T * p)
15577 {
15578 /* Establish scopes of routine texts and format texts */
15579   get_youngest_environs (p);
15580 /* Find non-local environs */
15581   get_non_local_environs (p, PRIMAL_SCOPE);
15582 /* PROC and FORMAT identities can now be assigned a scope */
15583   bind_scope_to_tags (p);
15584 /* Now check evertyhing else */
15585   scope_enclosed_clause (SUB (p), NO_VAR);
15586 }
15587 
15588 /* syntax.c*/
15589