parser-scope.c
1 //! @file parser-scope.c
2 //! @author J. Marcel van der Veer
3
4 //! @section Copyright
5 //!
6 //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
7 //! Copyright 2001-2024 J. Marcel van der Veer [algol68g@xs4all.nl].
8
9 //! @section License
10 //!
11 //! This program is free software; you can redistribute it and/or modify it
12 //! under the terms of the GNU General Public License as published by the
13 //! Free Software Foundation; either version 3 of the License, or
14 //! (at your option) any later version.
15 //!
16 //! This program is distributed in the hope that it will be useful, but
17 //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
19 //! more details. You should have received a copy of the GNU General Public
20 //! License along with this program. If not, see [http://www.gnu.org/licenses/].
21
22 //! @section Synopsis
23 //!
24 //! Static scope checker.
25
26 // A static scope checker inspects the source. Note that Algol 68 also
27 // needs dynamic scope checking. This phase concludes the parser.
28
29 #include "a68g.h"
30 #include "a68g-parser.h"
31
32 typedef struct TUPLE_T TUPLE_T;
33 typedef struct SCOPE_T SCOPE_T;
34
35 struct TUPLE_T
36 {
37 int level;
38 BOOL_T transient;
39 };
40
41 struct SCOPE_T
42 {
43 NODE_T *where;
44 TUPLE_T tuple;
45 SCOPE_T *next;
46 };
47
48 enum
49 { NOT_TRANSIENT = 0, TRANSIENT };
50
51 void gather_scopes_for_youngest (NODE_T *, SCOPE_T **);
52 void scope_statement (NODE_T *, SCOPE_T **);
53 void scope_enclosed_clause (NODE_T *, SCOPE_T **);
54 void scope_formula (NODE_T *, SCOPE_T **);
55 void scope_routine_text (NODE_T *, SCOPE_T **);
56
57 // Static scope checker, at run time we check dynamic scope as well.
58
59 // Static scope checker.
60 // Also a little preparation for the monitor:
61 // - indicates UNITs that can be interrupted.
62
63 //! @brief Scope_make_tuple.
64
65 TUPLE_T scope_make_tuple (int e, int t)
66 {
67 static TUPLE_T z;
68 LEVEL (&z) = e;
69 TRANSIENT (&z) = (BOOL_T) t;
70 return z;
71 }
72
73 //! @brief Link scope information into the list.
74
75 void scope_add (SCOPE_T ** sl, NODE_T * p, TUPLE_T tup)
76 {
77 if (sl != NO_VAR) {
78 SCOPE_T *ns = (SCOPE_T *) get_temp_heap_space ((unt) SIZE_ALIGNED (SCOPE_T));
79 WHERE (ns) = p;
80 TUPLE (ns) = tup;
81 NEXT (ns) = *sl;
82 *sl = ns;
83 }
84 }
85
86 //! @brief Scope_check.
87
88 BOOL_T scope_check (SCOPE_T * top, int mask, int dest)
89 {
90 int errors = 0;
91 // Transient names cannot be stored.
92 if (mask & TRANSIENT) {
93 for (SCOPE_T *s = top; s != NO_SCOPE; FORWARD (s)) {
94 if (TRANSIENT (&TUPLE (s)) & TRANSIENT) {
95 diagnostic (A68_ERROR, WHERE (s), ERROR_TRANSIENT_NAME);
96 STATUS_SET (WHERE (s), SCOPE_ERROR_MASK);
97 errors++;
98 }
99 }
100 }
101 // Potential scope violations.
102 for (SCOPE_T *s = top; s != NO_SCOPE; FORWARD (s)) {
103 if (dest < LEVEL (&TUPLE (s)) && !STATUS_TEST (WHERE (s), SCOPE_ERROR_MASK)) {
104 MOID_T *ws = MOID (WHERE (s));
105 if (ws != NO_MOID) {
106 if (IS_REF (ws) || IS (ws, PROC_SYMBOL) || IS (ws, FORMAT_SYMBOL) || IS (ws, UNION_SYMBOL)) {
107 diagnostic (A68_WARNING, WHERE (s), WARNING_SCOPE_STATIC, MOID (WHERE (s)), ATTRIBUTE (WHERE (s)));
108 }
109 }
110 STATUS_SET (WHERE (s), SCOPE_ERROR_MASK);
111 errors++;
112 }
113 }
114 return (BOOL_T) (errors == 0);
115 }
116
117 //! @brief Scope_check_multiple.
118
119 BOOL_T scope_check_multiple (SCOPE_T * top, int mask, SCOPE_T * dest)
120 {
121 BOOL_T no_err = A68_TRUE;
122 for (; dest != NO_SCOPE; FORWARD (dest)) {
123 no_err &= scope_check (top, mask, LEVEL (&TUPLE (dest)));
124 }
125 return no_err;
126 }
127
128 //! @brief Check_identifier_usage.
129
130 void check_identifier_usage (TAG_T * t, NODE_T * p)
131 {
132 for (; p != NO_NODE; FORWARD (p)) {
133 if (IS (p, IDENTIFIER) && TAX (p) == t && ATTRIBUTE (MOID (t)) != PROC_SYMBOL) {
134 diagnostic (A68_WARNING, p, WARNING_UNINITIALISED);
135 }
136 check_identifier_usage (t, SUB (p));
137 }
138 }
139
140 //! @brief Scope_find_youngest_outside.
141
142 TUPLE_T scope_find_youngest_outside (SCOPE_T * s, int treshold)
143 {
144 TUPLE_T z = scope_make_tuple (PRIMAL_SCOPE, NOT_TRANSIENT);
145 for (; s != NO_SCOPE; FORWARD (s)) {
146 if (LEVEL (&TUPLE (s)) > LEVEL (&z) && LEVEL (&TUPLE (s)) <= treshold) {
147 z = TUPLE (s);
148 }
149 }
150 return z;
151 }
152
153 //! @brief Scope_find_youngest.
154
155 TUPLE_T scope_find_youngest (SCOPE_T * s)
156 {
157 return scope_find_youngest_outside (s, INT_MAX);
158 }
159
160 // Routines for determining scope of ROUTINE TEXT or FORMAT TEXT.
161
162 //! @brief Get_declarer_elements.
163
164 void get_declarer_elements (NODE_T * p, SCOPE_T ** r, BOOL_T no_ref)
165 {
166 if (p != NO_NODE) {
167 if (IS (p, BOUNDS)) {
168 gather_scopes_for_youngest (SUB (p), r);
169 } else if (IS (p, INDICANT)) {
170 if (MOID (p) != NO_MOID && TAX (p) != NO_TAG && HAS_ROWS (MOID (p)) && no_ref) {
171 scope_add (r, p, scope_make_tuple (TAG_LEX_LEVEL (TAX (p)), NOT_TRANSIENT));
172 }
173 } else if (IS_REF (p)) {
174 get_declarer_elements (NEXT (p), r, A68_FALSE);
175 } else if (is_one_of (p, PROC_SYMBOL, UNION_SYMBOL, STOP)) {
176 ;
177 } else {
178 get_declarer_elements (SUB (p), r, no_ref);
179 get_declarer_elements (NEXT (p), r, no_ref);
180 }
181 }
182 }
183
184 //! @brief Gather_scopes_for_youngest.
185
186 void gather_scopes_for_youngest (NODE_T * p, SCOPE_T ** s)
187 {
188 for (; p != NO_NODE; FORWARD (p)) {
189 if ((is_one_of (p, ROUTINE_TEXT, FORMAT_TEXT, STOP)) && (YOUNGEST_ENVIRON (TAX (p)) == PRIMAL_SCOPE)) {
190 SCOPE_T *t = NO_SCOPE;
191 TUPLE_T tup;
192 gather_scopes_for_youngest (SUB (p), &t);
193 tup = scope_find_youngest_outside (t, LEX_LEVEL (p));
194 YOUNGEST_ENVIRON (TAX (p)) = LEVEL (&tup);
195 // Direct link into list iso "gather_scopes_for_youngest (SUB (p), s);".
196 if (t != NO_SCOPE) {
197 SCOPE_T *u = t;
198 while (NEXT (u) != NO_SCOPE) {
199 FORWARD (u);
200 }
201 NEXT (u) = *s;
202 (*s) = t;
203 }
204 } else if (is_one_of (p, IDENTIFIER, OPERATOR, STOP)) {
205 if (TAX (p) != NO_TAG && TAG_LEX_LEVEL (TAX (p)) != PRIMAL_SCOPE) {
206 scope_add (s, p, scope_make_tuple (TAG_LEX_LEVEL (TAX (p)), NOT_TRANSIENT));
207 }
208 } else if (IS (p, DECLARER)) {
209 get_declarer_elements (p, s, A68_TRUE);
210 } else {
211 gather_scopes_for_youngest (SUB (p), s);
212 }
213 }
214 }
215
216 //! @brief Get_youngest_environs.
217
218 void get_youngest_environs (NODE_T * p)
219 {
220 for (; p != NO_NODE; FORWARD (p)) {
221 if (is_one_of (p, ROUTINE_TEXT, FORMAT_TEXT, STOP)) {
222 SCOPE_T *s = NO_SCOPE;
223 TUPLE_T tup;
224 gather_scopes_for_youngest (SUB (p), &s);
225 tup = scope_find_youngest_outside (s, LEX_LEVEL (p));
226 YOUNGEST_ENVIRON (TAX (p)) = LEVEL (&tup);
227 } else {
228 get_youngest_environs (SUB (p));
229 }
230 }
231 }
232
233 //! @brief Bind_scope_to_tag.
234
235 void bind_scope_to_tag (NODE_T * p)
236 {
237 for (; p != NO_NODE; FORWARD (p)) {
238 if (IS (p, DEFINING_IDENTIFIER) && MOID (p) == M_FORMAT) {
239 if (IS (NEXT_NEXT (p), FORMAT_TEXT)) {
240 SCOPE (TAX (p)) = YOUNGEST_ENVIRON (TAX (NEXT_NEXT (p)));
241 SCOPE_ASSIGNED (TAX (p)) = A68_TRUE;
242 }
243 return;
244 } else if (IS (p, DEFINING_IDENTIFIER)) {
245 if (IS (NEXT_NEXT (p), ROUTINE_TEXT)) {
246 SCOPE (TAX (p)) = YOUNGEST_ENVIRON (TAX (NEXT_NEXT (p)));
247 SCOPE_ASSIGNED (TAX (p)) = A68_TRUE;
248 }
249 return;
250 } else {
251 bind_scope_to_tag (SUB (p));
252 }
253 }
254 }
255
256 //! @brief Bind_scope_to_tags.
257
258 void bind_scope_to_tags (NODE_T * p)
259 {
260 for (; p != NO_NODE; FORWARD (p)) {
261 if (is_one_of (p, PROCEDURE_DECLARATION, IDENTITY_DECLARATION, STOP)) {
262 bind_scope_to_tag (SUB (p));
263 } else {
264 bind_scope_to_tags (SUB (p));
265 }
266 }
267 }
268
269 //! @brief Scope_bounds.
270
271 void scope_bounds (NODE_T * p)
272 {
273 for (; p != NO_NODE; FORWARD (p)) {
274 if (IS (p, UNIT)) {
275 scope_statement (p, NO_VAR);
276 } else {
277 scope_bounds (SUB (p));
278 }
279 }
280 }
281
282 //! @brief Scope_declarer.
283
284 void scope_declarer (NODE_T * p)
285 {
286 if (p != NO_NODE) {
287 if (IS (p, BOUNDS)) {
288 scope_bounds (SUB (p));
289 } else if (IS (p, INDICANT)) {
290 ;
291 } else if (IS_REF (p)) {
292 scope_declarer (NEXT (p));
293 } else if (is_one_of (p, PROC_SYMBOL, UNION_SYMBOL, STOP)) {
294 ;
295 } else {
296 scope_declarer (SUB (p));
297 scope_declarer (NEXT (p));
298 }
299 }
300 }
301
302 //! @brief Scope_identity_declaration.
303
304 void scope_identity_declaration (NODE_T * p)
305 {
306 for (; p != NO_NODE; FORWARD (p)) {
307 scope_identity_declaration (SUB (p));
308 if (IS (p, DEFINING_IDENTIFIER)) {
309 NODE_T *unit = NEXT_NEXT (p);
310 SCOPE_T *s = NO_SCOPE;
311 TUPLE_T tup;
312 int z = PRIMAL_SCOPE;
313 if (ATTRIBUTE (MOID (TAX (p))) != PROC_SYMBOL) {
314 check_identifier_usage (TAX (p), unit);
315 }
316 scope_statement (unit, &s);
317 (void) scope_check (s, TRANSIENT, LEX_LEVEL (p));
318 tup = scope_find_youngest (s);
319 z = LEVEL (&tup);
320 if (z < LEX_LEVEL (p)) {
321 SCOPE (TAX (p)) = z;
322 SCOPE_ASSIGNED (TAX (p)) = A68_TRUE;
323 }
324 STATUS_SET (unit, INTERRUPTIBLE_MASK);
325 return;
326 }
327 }
328 }
329
330 //! @brief Scope_variable_declaration.
331
332 void scope_variable_declaration (NODE_T * p)
333 {
334 for (; p != NO_NODE; FORWARD (p)) {
335 scope_variable_declaration (SUB (p));
336 if (IS (p, DECLARER)) {
337 scope_declarer (SUB (p));
338 } else if (IS (p, DEFINING_IDENTIFIER)) {
339 if (whether (p, DEFINING_IDENTIFIER, ASSIGN_SYMBOL, UNIT, STOP)) {
340 NODE_T *unit = NEXT_NEXT (p);
341 SCOPE_T *s = NO_SCOPE;
342 check_identifier_usage (TAX (p), unit);
343 scope_statement (unit, &s);
344 (void) scope_check (s, TRANSIENT, LEX_LEVEL (p));
345 STATUS_SET (unit, INTERRUPTIBLE_MASK);
346 return;
347 }
348 }
349 }
350 }
351
352 //! @brief Scope_procedure_declaration.
353
354 void scope_procedure_declaration (NODE_T * p)
355 {
356 for (; p != NO_NODE; FORWARD (p)) {
357 scope_procedure_declaration (SUB (p));
358 if (is_one_of (p, DEFINING_IDENTIFIER, DEFINING_OPERATOR, STOP)) {
359 NODE_T *unit = NEXT_NEXT (p);
360 SCOPE_T *s = NO_SCOPE;
361 scope_statement (unit, &s);
362 (void) scope_check (s, NOT_TRANSIENT, LEX_LEVEL (p));
363 STATUS_SET (unit, INTERRUPTIBLE_MASK);
364 return;
365 }
366 }
367 }
368
369 //! @brief Scope_declaration_list.
370
371 void scope_declaration_list (NODE_T * p)
372 {
373 if (p != NO_NODE) {
374 if (IS (p, IDENTITY_DECLARATION)) {
375 scope_identity_declaration (SUB (p));
376 } else if (IS (p, VARIABLE_DECLARATION)) {
377 scope_variable_declaration (SUB (p));
378 } else if (IS (p, MODE_DECLARATION)) {
379 scope_declarer (SUB (p));
380 } else if (IS (p, PRIORITY_DECLARATION)) {
381 ;
382 } else if (IS (p, PROCEDURE_DECLARATION)) {
383 scope_procedure_declaration (SUB (p));
384 } else if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) {
385 scope_procedure_declaration (SUB (p));
386 } else if (is_one_of (p, BRIEF_OPERATOR_DECLARATION, OPERATOR_DECLARATION, STOP)) {
387 scope_procedure_declaration (SUB (p));
388 } else {
389 scope_declaration_list (SUB (p));
390 scope_declaration_list (NEXT (p));
391 }
392 }
393 }
394
395 //! @brief Scope_arguments.
396
397 void scope_arguments (NODE_T * p)
398 {
399 for (; p != NO_NODE; FORWARD (p)) {
400 if (IS (p, UNIT)) {
401 SCOPE_T *s = NO_SCOPE;
402 scope_statement (p, &s);
403 (void) scope_check (s, TRANSIENT, LEX_LEVEL (p));
404 } else {
405 scope_arguments (SUB (p));
406 }
407 }
408 }
409
410 //! @brief Is_coercion.
411
412 BOOL_T is_coercion (NODE_T * p)
413 {
414 if (p != NO_NODE) {
415 switch (ATTRIBUTE (p)) {
416 case DEPROCEDURING:
417 case DEREFERENCING:
418 case UNITING:
419 case ROWING:
420 case WIDENING:
421 case VOIDING:
422 case PROCEDURING: {
423 return A68_TRUE;
424 }
425 default: {
426 return A68_FALSE;
427 }
428 }
429 } else {
430 return A68_FALSE;
431 }
432 }
433
434 //! @brief Scope_coercion.
435
436 void scope_coercion (NODE_T * p, SCOPE_T ** s)
437 {
438 if (is_coercion (p)) {
439 if (IS (p, VOIDING)) {
440 scope_coercion (SUB (p), NO_VAR);
441 } else if (IS (p, DEREFERENCING)) {
442 // Leave this to the dynamic scope checker.
443 scope_coercion (SUB (p), NO_VAR);
444 } else if (IS (p, DEPROCEDURING)) {
445 scope_coercion (SUB (p), NO_VAR);
446 } else if (IS (p, ROWING)) {
447 SCOPE_T *z = NO_SCOPE;
448 scope_coercion (SUB (p), &z);
449 (void) scope_check (z, TRANSIENT, LEX_LEVEL (p));
450 if (IS_REF_FLEX (MOID (SUB (p)))) {
451 scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), TRANSIENT));
452 } else {
453 scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), NOT_TRANSIENT));
454 }
455 } else if (IS (p, PROCEDURING)) {
456 // Can only be a JUMP.
457 NODE_T *q = SUB_SUB (p);
458 if (IS (q, GOTO_SYMBOL)) {
459 FORWARD (q);
460 }
461 scope_add (s, q, scope_make_tuple (TAG_LEX_LEVEL (TAX (q)), NOT_TRANSIENT));
462 } else if (IS (p, UNITING)) {
463 SCOPE_T *z = NO_SCOPE;
464 scope_coercion (SUB (p), &z);
465 if (z != NO_SCOPE) {
466 (void) scope_check (z, TRANSIENT, LEX_LEVEL (p));
467 scope_add (s, p, scope_find_youngest (z));
468 }
469 } else {
470 scope_coercion (SUB (p), s);
471 }
472 } else {
473 scope_statement (p, s);
474 }
475 }
476
477 //! @brief Scope_format_text.
478
479 void scope_format_text (NODE_T * p, SCOPE_T ** s)
480 {
481 for (; p != NO_NODE; FORWARD (p)) {
482 if (IS (p, FORMAT_PATTERN)) {
483 scope_enclosed_clause (SUB (NEXT_SUB (p)), s);
484 } else if (IS (p, FORMAT_ITEM_G) && NEXT (p) != NO_NODE) {
485 scope_enclosed_clause (SUB_NEXT (p), s);
486 } else if (IS (p, DYNAMIC_REPLICATOR)) {
487 scope_enclosed_clause (SUB (NEXT_SUB (p)), s);
488 } else {
489 scope_format_text (SUB (p), s);
490 }
491 }
492 }
493
494 //! @brief Scope_operand.
495
496 void scope_operand (NODE_T * p, SCOPE_T ** s)
497 {
498 if (IS (p, MONADIC_FORMULA)) {
499 scope_operand (NEXT_SUB (p), s);
500 } else if (IS (p, FORMULA)) {
501 scope_formula (p, s);
502 } else if (IS (p, SECONDARY)) {
503 scope_statement (SUB (p), s);
504 }
505 }
506
507 //! @brief Scope_formula.
508
509 void scope_formula (NODE_T * p, SCOPE_T ** s)
510 {
511 NODE_T *q = SUB (p);
512 SCOPE_T *s2 = NO_SCOPE;
513 scope_operand (q, &s2);
514 (void) scope_check (s2, TRANSIENT, LEX_LEVEL (p));
515 if (NEXT (q) != NO_NODE) {
516 SCOPE_T *s3 = NO_SCOPE;
517 scope_operand (NEXT_NEXT (q), &s3);
518 (void) scope_check (s3, TRANSIENT, LEX_LEVEL (p));
519 }
520 (void) s;
521 }
522
523 //! @brief Scope_routine_text.
524
525 void scope_routine_text (NODE_T * p, SCOPE_T ** s)
526 {
527 NODE_T *q = SUB (p), *routine = (IS (q, PARAMETER_PACK) ? NEXT (q) : q);
528 SCOPE_T *x = NO_SCOPE;
529 scope_statement (NEXT_NEXT (routine), &x);
530 (void) scope_check (x, TRANSIENT, LEX_LEVEL (p));
531 TUPLE_T routine_tuple = scope_make_tuple (YOUNGEST_ENVIRON (TAX (p)), NOT_TRANSIENT);
532 scope_add (s, p, routine_tuple);
533 }
534
535 //! @brief Scope_statement.
536
537 void scope_statement (NODE_T * p, SCOPE_T ** s)
538 {
539 if (is_coercion (p)) {
540 scope_coercion (p, s);
541 } else if (is_one_of (p, PRIMARY, SECONDARY, TERTIARY, UNIT, STOP)) {
542 scope_statement (SUB (p), s);
543 } else if (is_one_of (p, NIHIL, STOP)) {
544 scope_add (s, p, scope_make_tuple (PRIMAL_SCOPE, NOT_TRANSIENT));
545 } else if (IS (p, DENOTATION)) {
546 ;
547 } else if (IS (p, IDENTIFIER)) {
548 if (IS_REF (MOID (p))) {
549 if (PRIO (TAX (p)) == PARAMETER_IDENTIFIER) {
550 scope_add (s, p, scope_make_tuple (TAG_LEX_LEVEL (TAX (p)) - 1, NOT_TRANSIENT));
551 } else {
552 if (HEAP (TAX (p)) == HEAP_SYMBOL) {
553 scope_add (s, p, scope_make_tuple (PRIMAL_SCOPE, NOT_TRANSIENT));
554 } else if (SCOPE_ASSIGNED (TAX (p))) {
555 scope_add (s, p, scope_make_tuple (SCOPE (TAX (p)), NOT_TRANSIENT));
556 } else {
557 scope_add (s, p, scope_make_tuple (TAG_LEX_LEVEL (TAX (p)), NOT_TRANSIENT));
558 }
559 }
560 } else if (ATTRIBUTE (MOID (p)) == PROC_SYMBOL && SCOPE_ASSIGNED (TAX (p)) == A68_TRUE) {
561 scope_add (s, p, scope_make_tuple (SCOPE (TAX (p)), NOT_TRANSIENT));
562 } else if (MOID (p) == M_FORMAT && SCOPE_ASSIGNED (TAX (p)) == A68_TRUE) {
563 scope_add (s, p, scope_make_tuple (SCOPE (TAX (p)), NOT_TRANSIENT));
564 }
565 } else if (IS (p, ENCLOSED_CLAUSE)) {
566 scope_enclosed_clause (SUB (p), s);
567 } else if (IS (p, CALL)) {
568 SCOPE_T *x = NO_SCOPE;
569 scope_statement (SUB (p), &x);
570 (void) scope_check (x, NOT_TRANSIENT, LEX_LEVEL (p));
571 scope_arguments (NEXT_SUB (p));
572 } else if (IS (p, SLICE)) {
573 SCOPE_T *x = NO_SCOPE;
574 MOID_T *m = MOID (SUB (p));
575 if (IS_REF (m)) {
576 if (ATTRIBUTE (SUB (p)) == PRIMARY && ATTRIBUTE (SUB_SUB (p)) == SLICE) {
577 scope_statement (SUB (p), s);
578 } else {
579 scope_statement (SUB (p), &x);
580 (void) scope_check (x, NOT_TRANSIENT, LEX_LEVEL (p));
581 }
582 if (IS_FLEX (SUB (m))) {
583 scope_add (s, SUB (p), scope_make_tuple (LEX_LEVEL (p), TRANSIENT));
584 }
585 scope_bounds (SUB (NEXT_SUB (p)));
586 }
587 if (IS_REF (MOID (p))) {
588 scope_add (s, p, scope_find_youngest (x));
589 }
590 } else if (IS (p, FORMAT_TEXT)) {
591 SCOPE_T *x = NO_SCOPE;
592 scope_format_text (SUB (p), &x);
593 scope_add (s, p, scope_find_youngest (x));
594 } else if (IS (p, CAST)) {
595 SCOPE_T *x = NO_SCOPE;
596 scope_enclosed_clause (SUB (NEXT_SUB (p)), &x);
597 (void) scope_check (x, NOT_TRANSIENT, LEX_LEVEL (p));
598 scope_add (s, p, scope_find_youngest (x));
599 } else if (IS (p, SELECTION)) {
600 SCOPE_T *ns = NO_SCOPE;
601 scope_statement (NEXT_SUB (p), &ns);
602 (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (p));
603 if (is_ref_refety_flex (MOID (NEXT_SUB (p)))) {
604 scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), TRANSIENT));
605 }
606 scope_add (s, p, scope_find_youngest (ns));
607 } else if (IS (p, GENERATOR)) {
608 if (IS (SUB (p), LOC_SYMBOL)) {
609 if (NON_LOCAL (p) != NO_TABLE) {
610 scope_add (s, p, scope_make_tuple (LEVEL (NON_LOCAL (p)), NOT_TRANSIENT));
611 } else {
612 scope_add (s, p, scope_make_tuple (LEX_LEVEL (p), NOT_TRANSIENT));
613 }
614 } else {
615 scope_add (s, p, scope_make_tuple (PRIMAL_SCOPE, NOT_TRANSIENT));
616 }
617 scope_declarer (SUB (NEXT_SUB (p)));
618 } else if (IS (p, DIAGONAL_FUNCTION)) {
619 NODE_T *q = SUB (p);
620 SCOPE_T *ns = NO_SCOPE;
621 if (IS (q, TERTIARY)) {
622 scope_statement (SUB (q), &ns);
623 (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
624 ns = NO_SCOPE;
625 FORWARD (q);
626 }
627 scope_statement (SUB_NEXT (q), &ns);
628 (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
629 scope_add (s, p, scope_find_youngest (ns));
630 } else if (IS (p, TRANSPOSE_FUNCTION)) {
631 NODE_T *q = SUB (p);
632 SCOPE_T *ns = NO_SCOPE;
633 scope_statement (SUB_NEXT (q), &ns);
634 (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
635 scope_add (s, p, scope_find_youngest (ns));
636 } else if (IS (p, ROW_FUNCTION)) {
637 NODE_T *q = SUB (p);
638 SCOPE_T *ns = NO_SCOPE;
639 if (IS (q, TERTIARY)) {
640 scope_statement (SUB (q), &ns);
641 (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
642 ns = NO_SCOPE;
643 FORWARD (q);
644 }
645 scope_statement (SUB_NEXT (q), &ns);
646 (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
647 scope_add (s, p, scope_find_youngest (ns));
648 } else if (IS (p, COLUMN_FUNCTION)) {
649 NODE_T *q = SUB (p);
650 SCOPE_T *ns = NO_SCOPE;
651 if (IS (q, TERTIARY)) {
652 scope_statement (SUB (q), &ns);
653 (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
654 ns = NO_SCOPE;
655 FORWARD (q);
656 }
657 scope_statement (SUB_NEXT (q), &ns);
658 (void) scope_check (ns, NOT_TRANSIENT, LEX_LEVEL (q));
659 scope_add (s, p, scope_find_youngest (ns));
660 } else if (IS (p, FORMULA)) {
661 scope_formula (p, s);
662 } else if (IS (p, ASSIGNATION)) {
663 NODE_T *unit = NEXT (NEXT_SUB (p));
664 SCOPE_T *ns = NO_SCOPE, *nd = NO_SCOPE;
665 TUPLE_T tup;
666 scope_statement (SUB_SUB (p), &nd);
667 scope_statement (unit, &ns);
668 (void) scope_check_multiple (ns, TRANSIENT, nd);
669 tup = scope_find_youngest (nd);
670 scope_add (s, p, scope_make_tuple (LEVEL (&tup), NOT_TRANSIENT));
671 } else if (IS (p, ROUTINE_TEXT)) {
672 scope_routine_text (p, s);
673 } else if (is_one_of (p, IDENTITY_RELATION, AND_FUNCTION, OR_FUNCTION, STOP)) {
674 SCOPE_T *n = NO_SCOPE;
675 scope_statement (SUB (p), &n);
676 scope_statement (NEXT (NEXT_SUB (p)), &n);
677 (void) scope_check (n, NOT_TRANSIENT, LEX_LEVEL (p));
678 } else if (IS (p, ASSERTION)) {
679 SCOPE_T *n = NO_SCOPE;
680 scope_enclosed_clause (SUB (NEXT_SUB (p)), &n);
681 (void) scope_check (n, NOT_TRANSIENT, LEX_LEVEL (p));
682 } else if (is_one_of (p, JUMP, SKIP, STOP)) {
683 ;
684 }
685 }
686
687 //! @brief Scope_statement_list.
688
689 void scope_statement_list (NODE_T * p, SCOPE_T ** s)
690 {
691 for (; p != NO_NODE; FORWARD (p)) {
692 if (IS (p, UNIT)) {
693 STATUS_SET (p, INTERRUPTIBLE_MASK);
694 scope_statement (p, s);
695 } else {
696 scope_statement_list (SUB (p), s);
697 }
698 }
699 }
700
701 //! @brief Scope_serial_clause.
702
703 void scope_serial_clause (NODE_T * p, SCOPE_T ** s, BOOL_T terminator)
704 {
705 if (p != NO_NODE) {
706 if (IS (p, INITIALISER_SERIES)) {
707 scope_serial_clause (SUB (p), s, A68_FALSE);
708 scope_serial_clause (NEXT (p), s, terminator);
709 } else if (IS (p, DECLARATION_LIST)) {
710 scope_declaration_list (SUB (p));
711 } else if (is_one_of (p, LABEL, SEMI_SYMBOL, EXIT_SYMBOL, STOP)) {
712 scope_serial_clause (NEXT (p), s, terminator);
713 } else if (is_one_of (p, SERIAL_CLAUSE, ENQUIRY_CLAUSE, STOP)) {
714 if (NEXT (p) != NO_NODE) {
715 int j = ATTRIBUTE (NEXT (p));
716 if (j == EXIT_SYMBOL || j == END_SYMBOL || j == CLOSE_SYMBOL) {
717 scope_serial_clause (SUB (p), s, A68_TRUE);
718 } else {
719 scope_serial_clause (SUB (p), s, A68_FALSE);
720 }
721 } else {
722 scope_serial_clause (SUB (p), s, A68_TRUE);
723 }
724 scope_serial_clause (NEXT (p), s, terminator);
725 } else if (IS (p, LABELED_UNIT)) {
726 scope_serial_clause (SUB (p), s, terminator);
727 } else if (IS (p, UNIT)) {
728 STATUS_SET (p, INTERRUPTIBLE_MASK);
729 if (terminator) {
730 scope_statement (p, s);
731 } else {
732 scope_statement (p, NO_VAR);
733 }
734 }
735 }
736 }
737
738 //! @brief Scope_closed_clause.
739
740 void scope_closed_clause (NODE_T * p, SCOPE_T ** s)
741 {
742 if (p != NO_NODE) {
743 if (IS (p, SERIAL_CLAUSE)) {
744 scope_serial_clause (p, s, A68_TRUE);
745 } else if (is_one_of (p, OPEN_SYMBOL, BEGIN_SYMBOL, STOP)) {
746 scope_closed_clause (NEXT (p), s);
747 }
748 }
749 }
750
751 //! @brief Scope_collateral_clause.
752
753 void scope_collateral_clause (NODE_T * p, SCOPE_T ** s)
754 {
755 if (p != NO_NODE) {
756 if (!(whether (p, BEGIN_SYMBOL, END_SYMBOL, STOP) || whether (p, OPEN_SYMBOL, CLOSE_SYMBOL, STOP))) {
757 scope_statement_list (p, s);
758 }
759 }
760 }
761
762 //! @brief Scope_conditional_clause.
763
764 void scope_conditional_clause (NODE_T * p, SCOPE_T ** s)
765 {
766 scope_serial_clause (NEXT_SUB (p), NO_VAR, A68_TRUE);
767 FORWARD (p);
768 scope_serial_clause (NEXT_SUB (p), s, A68_TRUE);
769 if ((FORWARD (p)) != NO_NODE) {
770 if (is_one_of (p, ELSE_PART, CHOICE, STOP)) {
771 scope_serial_clause (NEXT_SUB (p), s, A68_TRUE);
772 } else if (is_one_of (p, ELIF_PART, BRIEF_ELIF_PART, STOP)) {
773 scope_conditional_clause (SUB (p), s);
774 }
775 }
776 }
777
778 //! @brief Scope_case_clause.
779
780 void scope_case_clause (NODE_T * p, SCOPE_T ** s)
781 {
782 SCOPE_T *n = NO_SCOPE;
783 scope_serial_clause (NEXT_SUB (p), &n, A68_TRUE);
784 (void) scope_check (n, NOT_TRANSIENT, LEX_LEVEL (p));
785 FORWARD (p);
786 scope_statement_list (NEXT_SUB (p), s);
787 if ((FORWARD (p)) != NO_NODE) {
788 if (is_one_of (p, OUT_PART, CHOICE, STOP)) {
789 scope_serial_clause (NEXT_SUB (p), s, A68_TRUE);
790 } else if (is_one_of (p, CASE_OUSE_PART, BRIEF_OUSE_PART, STOP)) {
791 scope_case_clause (SUB (p), s);
792 } else if (is_one_of (p, CONFORMITY_OUSE_PART, BRIEF_CONFORMITY_OUSE_PART, STOP)) {
793 scope_case_clause (SUB (p), s);
794 }
795 }
796 }
797
798 //! @brief Scope_loop_clause.
799
800 void scope_loop_clause (NODE_T * p)
801 {
802 if (p != NO_NODE) {
803 if (IS (p, FOR_PART)) {
804 scope_loop_clause (NEXT (p));
805 } else if (is_one_of (p, FROM_PART, BY_PART, TO_PART, STOP)) {
806 scope_statement (NEXT_SUB (p), NO_VAR);
807 scope_loop_clause (NEXT (p));
808 } else if (IS (p, WHILE_PART)) {
809 scope_serial_clause (NEXT_SUB (p), NO_VAR, A68_TRUE);
810 scope_loop_clause (NEXT (p));
811 } else if (is_one_of (p, DO_PART, ALT_DO_PART, STOP)) {
812 NODE_T *do_p = NEXT_SUB (p), *un_p;
813 if (IS (do_p, SERIAL_CLAUSE)) {
814 scope_serial_clause (do_p, NO_VAR, A68_TRUE);
815 un_p = NEXT (do_p);
816 } else {
817 un_p = do_p;
818 }
819 if (un_p != NO_NODE && IS (un_p, UNTIL_PART)) {
820 scope_serial_clause (NEXT_SUB (un_p), NO_VAR, A68_TRUE);
821 }
822 }
823 }
824 }
825
826 //! @brief Scope_enclosed_clause.
827
828 void scope_enclosed_clause (NODE_T * p, SCOPE_T ** s)
829 {
830 if (IS (p, ENCLOSED_CLAUSE)) {
831 scope_enclosed_clause (SUB (p), s);
832 } else if (IS (p, CLOSED_CLAUSE)) {
833 scope_closed_clause (SUB (p), s);
834 } else if (is_one_of (p, COLLATERAL_CLAUSE, PARALLEL_CLAUSE, STOP)) {
835 scope_collateral_clause (SUB (p), s);
836 } else if (IS (p, CONDITIONAL_CLAUSE)) {
837 scope_conditional_clause (SUB (p), s);
838 } else if (is_one_of (p, CASE_CLAUSE, CONFORMITY_CLAUSE, STOP)) {
839 scope_case_clause (SUB (p), s);
840 } else if (IS (p, LOOP_CLAUSE)) {
841 scope_loop_clause (SUB (p));
842 }
843 }
844
845 //! @brief Whether a symbol table contains no (anonymous) definition.
846
847 BOOL_T empty_table (TABLE_T * t)
848 {
849 if (IDENTIFIERS (t) == NO_TAG) {
850 return (BOOL_T) (OPERATORS (t) == NO_TAG && INDICANTS (t) == NO_TAG);
851 } else if (PRIO (IDENTIFIERS (t)) == LOOP_IDENTIFIER && NEXT (IDENTIFIERS (t)) == NO_TAG) {
852 return (BOOL_T) (OPERATORS (t) == NO_TAG && INDICANTS (t) == NO_TAG);
853 } else if (PRIO (IDENTIFIERS (t)) == SPECIFIER_IDENTIFIER && NEXT (IDENTIFIERS (t)) == NO_TAG) {
854 return (BOOL_T) (OPERATORS (t) == NO_TAG && INDICANTS (t) == NO_TAG);
855 } else {
856 return A68_FALSE;
857 }
858 }
859
860 //! @brief Indicate non-local environs.
861
862 void get_non_local_environs (NODE_T * p, int max)
863 {
864 for (; p != NO_NODE; FORWARD (p)) {
865 if (IS (p, ROUTINE_TEXT)) {
866 get_non_local_environs (SUB (p), LEX_LEVEL (SUB (p)));
867 } else if (IS (p, FORMAT_TEXT)) {
868 get_non_local_environs (SUB (p), LEX_LEVEL (SUB (p)));
869 } else {
870 get_non_local_environs (SUB (p), max);
871 NON_LOCAL (p) = NO_TABLE;
872 if (TABLE (p) != NO_TABLE) {
873 TABLE_T *q = TABLE (p);
874 while (q != NO_TABLE && empty_table (q)
875 && PREVIOUS (q) != NO_TABLE && LEVEL (PREVIOUS (q)) >= max) {
876 NON_LOCAL (p) = PREVIOUS (q);
877 q = PREVIOUS (q);
878 }
879 }
880 }
881 }
882 }
883
884 //! @brief Scope_checker.
885
886 void scope_checker (NODE_T * p)
887 {
888 // Establish scopes of routine texts and format texts.
889 get_youngest_environs (p);
890 // Find non-local environs.
891 get_non_local_environs (p, PRIMAL_SCOPE);
892 // PROC and FORMAT identities can now be assigned a scope.
893 bind_scope_to_tags (p);
894 // Now check evertyhing else.
895 scope_enclosed_clause (SUB (p), NO_VAR);
896 }
© 2002-2024 J.M. van der Veer (jmvdveer@xs4all.nl)
|