/* Mode table management. Copyright (C) 2001-2023 J. Marcel van der Veer. Copyright (C) 2025 Jose E. Marchesi. Original implementation by J. Marcel van der Veer. Adapted for GCC by Jose E. Marchesi. GCC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. GCC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GCC; see the file COPYING3. If not see . */ #include "config.h" #include "system.h" #include "coretypes.h" #include "a68.h" /* * Mode collection, equivalencing and derived modes. */ /* Few forward references. */ static MOID_T *get_mode_from_declarer (NODE_T *p); /* * Mode service routines. */ /* Count bounds in declarer in tree. */ static int count_bounds (NODE_T *p) { if (p == NO_NODE) return 0; else { if (IS (p, BOUND)) return 1 + count_bounds (NEXT (p)); else return count_bounds (NEXT (p)) + count_bounds (SUB (p)); } } /* Count number of SHORTs or LONGs. */ static int count_sizety (NODE_T *p) { if (p == NO_NODE) return 0; else if (IS (p, LONGETY)) return count_sizety (SUB (p)) + count_sizety (NEXT (p)); else if (IS (p, SHORTETY)) return count_sizety (SUB (p)) + count_sizety (NEXT (p)); else if (IS (p, LONG_SYMBOL)) return 1; else if (IS (p, SHORT_SYMBOL)) return -1; else return 0; } /* Count moids in a pack. */ int a68_count_pack_members (PACK_T *u) { int k = 0; for (; u != NO_PACK; FORWARD (u)) k++; return k; } /* Replace a mode by its equivalent mode. */ static void resolve_equivalent (MOID_T **m) { while ((*m) != NO_MOID && EQUIVALENT ((*m)) != NO_MOID && (*m) != EQUIVALENT (*m)) { (*m) = EQUIVALENT (*m); } } /* Reset moid. */ static void reset_moid_tree (NODE_T *p) { for (; p != NO_NODE; FORWARD (p)) { MOID (p) = NO_MOID; reset_moid_tree (SUB (p)); } } /* Renumber moids. */ void a68_renumber_moids (MOID_T *p, int n) { if (p != NO_MOID) { NUMBER (p) = n; a68_renumber_moids (NEXT (p), n + 1); } } /* See whether a mode equivalent to the mode M exists in the global mode table, and return it. Return NO_MOID if no equivalent mode is found. */ MOID_T * a68_search_equivalent_mode (MOID_T *m) { for (MOID_T *head = TOP_MOID (&A68_JOB); head != NO_MOID; FORWARD (head)) { if (a68_prove_moid_equivalence (head, m)) return head; } return NO_MOID; } /* Register mode in the global mode table, if mode is unique. */ MOID_T * a68_register_extra_mode (MOID_T **z, MOID_T *u) { /* If we already know this mode, return the existing entry; otherwise link it in. */ for (MOID_T *head = TOP_MOID (&A68_JOB); head != NO_MOID; FORWARD (head)) { if (a68_prove_moid_equivalence (head, u)) return head; } /* Link to chain and exit. */ NUMBER (u) = A68 (mode_count)++; NEXT (u) = (*z); return *z = u; } /* Create a new mode. */ MOID_T * a68_create_mode (int att, int dim, NODE_T *node, MOID_T *sub, PACK_T *pack) { MOID_T *new_mode = a68_new_moid (); if (sub == NO_MOID) { if (att == REF_SYMBOL || att == FLEX_SYMBOL || att == ROW_SYMBOL) gcc_unreachable (); } USE (new_mode) = false; ATTRIBUTE (new_mode) = att; DIM (new_mode) = dim; NODE (new_mode) = node; HAS_ROWS (new_mode) = (att == ROW_SYMBOL); SUB (new_mode) = sub; PACK (new_mode) = pack; NEXT (new_mode) = NO_MOID; EQUIVALENT (new_mode) = NO_MOID; SLICE (new_mode) = NO_MOID; DEFLEXED (new_mode) = NO_MOID; NAME (new_mode) = NO_MOID; MULTIPLE (new_mode) = NO_MOID; ROWED (new_mode) = NO_MOID; return new_mode; } /* Create a new mode and add it to chain Z. */ MOID_T * a68_add_mode (MOID_T **z, int att, int dim, NODE_T *node, MOID_T *sub, PACK_T *pack) { MOID_T *new_mode = a68_create_mode (att, dim, node, sub, pack); return a68_register_extra_mode (z, new_mode); } /* Contract a UNION. */ void a68_contract_union (MOID_T *u) { for (PACK_T *s = PACK (u); s != NO_PACK; FORWARD (s)) { PACK_T *t = s; while (t != NO_PACK) { if (NEXT (t) != NO_PACK && MOID (NEXT (t)) == MOID (s)) { MOID (t) = MOID (t); NEXT (t) = NEXT_NEXT (t); } else FORWARD (t); } } } /* Absorb UNION pack. */ PACK_T * a68_absorb_union_pack (PACK_T * u) { PACK_T *z; bool siga; do { z = NO_PACK; siga = false; for (PACK_T *t = u; t != NO_PACK; FORWARD (t)) { if (IS (MOID (t), UNION_SYMBOL)) { siga = true; for (PACK_T *s = PACK (MOID (t)); s != NO_PACK; FORWARD (s)) (void) a68_add_mode_to_pack (&z, MOID (s), NO_TEXT, NODE (s)); } else { (void) a68_add_mode_to_pack (&z, MOID (t), NO_TEXT, NODE (t)); } } u = z; } while (siga); return z; } /* Add row and its slices to chain, recursively. */ static MOID_T * add_row (MOID_T **p, int dim, MOID_T *sub, NODE_T *n, bool derivate) { MOID_T *q = a68_add_mode (p, ROW_SYMBOL, dim, n, sub, NO_PACK); DERIVATE (q) |= derivate; if (dim > 1) SLICE (q) = add_row (&NEXT (q), dim - 1, sub, n, derivate); else SLICE (q) = sub; return q; } /* Add a moid to a pack, maybe with a (field) name. */ void a68_add_mode_to_pack (PACK_T **p, MOID_T *m, const char *text, NODE_T *node) { PACK_T *z = a68_new_pack (); MOID (z) = m; TEXT (z) = text; NODE (z) = node; NEXT (z) = *p; PREVIOUS (z) = NO_PACK; if (NEXT (z) != NO_PACK) PREVIOUS (NEXT (z)) = z; /* Link in chain. */ *p = z; } /* Add a moid to a pack, maybe with a (field) name. */ void a68_add_mode_to_pack_end (PACK_T **p, MOID_T *m, const char *text, NODE_T *node) { PACK_T *z = a68_new_pack (); MOID (z) = m; TEXT (z) = text; NODE (z) = node; NEXT (z) = NO_PACK; if (NEXT (z) != NO_PACK) PREVIOUS (NEXT (z)) = z; /* Link in chain. */ while ((*p) != NO_PACK) p = &(NEXT (*p)); PREVIOUS (z) = (*p); (*p) = z; } /* Absorb UNION members. */ static void absorb_unions (MOID_T *m) { /* UNION (A, UNION (B, C)) = UNION (A, B, C) or UNION (A, UNION (A, B)) = UNION (A, B). */ for (; m != NO_MOID; FORWARD (m)) { if (IS (m, UNION_SYMBOL)) PACK (m) = a68_absorb_union_pack (PACK (m)); } } /* Contract UNIONs. */ static void contract_unions (MOID_T *m) { /* UNION (A, B, A) -> UNION (A, B). */ for (; m != NO_MOID; FORWARD (m)) { if (IS (m, UNION_SYMBOL) && EQUIVALENT (m) == NO_MOID) a68_contract_union (m); } } /* * Routines to collect MOIDs from the program text. */ /* Search standard mode in standard environ. */ static MOID_T * search_standard_mode (int sizety, NODE_T *indicant) { /* Search standard mode. */ for (MOID_T *p = TOP_MOID (&A68_JOB); p != NO_MOID; FORWARD (p)) { if (IS (p, STANDARD) && DIM (p) == sizety && NSYMBOL (NODE (p)) == NSYMBOL (indicant)) return p; } /* Map onto greater precision. */ if (sizety < 0) return search_standard_mode (sizety + 1, indicant); else if (sizety > 0) return search_standard_mode (sizety - 1, indicant); else return NO_MOID; } /* Collect mode from STRUCT field. */ static void get_mode_from_struct_field (NODE_T *p, PACK_T **u) { if (p != NO_NODE) { if (IS (p, IDENTIFIER)) { ATTRIBUTE (p) = FIELD_IDENTIFIER; (void) a68_add_mode_to_pack (u, NO_MOID, NSYMBOL (p), p); } else if (IS (p, DECLARER)) { MOID_T *new_one = get_mode_from_declarer (p); get_mode_from_struct_field (NEXT (p), u); for (PACK_T *t = *u; t && MOID (t) == NO_MOID; FORWARD (t)) { MOID (t) = new_one; MOID (NODE (t)) = new_one; } } else { get_mode_from_struct_field (NEXT (p), u); get_mode_from_struct_field (SUB (p), u); } } } /* Collect MODE from formal pack. */ static void get_mode_from_formal_pack (NODE_T *p, PACK_T **u) { if (p != NO_NODE) { if (IS (p, DECLARER)) { get_mode_from_formal_pack (NEXT (p), u); MOID_T *z = get_mode_from_declarer (p); (void) a68_add_mode_to_pack (u, z, NO_TEXT, p); } else { get_mode_from_formal_pack (NEXT (p), u); get_mode_from_formal_pack (SUB (p), u); } } } /* Collect MODE or VOID from formal UNION pack. */ static void get_mode_from_union_pack (NODE_T *p, PACK_T **u) { if (p != NO_NODE) { if (IS (p, DECLARER) || IS (p, VOID_SYMBOL)) { get_mode_from_union_pack (NEXT (p), u); MOID_T *z = get_mode_from_declarer (p); (void) a68_add_mode_to_pack (u, z, NO_TEXT, p); } else { get_mode_from_union_pack (NEXT (p), u); get_mode_from_union_pack (SUB (p), u); } } } /* Collect mode from PROC, OP pack. */ static void get_mode_from_routine_pack (NODE_T *p, PACK_T **u) { if (p != NO_NODE) { if (IS (p, IDENTIFIER)) (void) a68_add_mode_to_pack (u, NO_MOID, NO_TEXT, p); else if (IS (p, DECLARER)) { MOID_T *z = get_mode_from_declarer (p); for (PACK_T *t = *u; t != NO_PACK && MOID (t) == NO_MOID; FORWARD (t)) { MOID (t) = z; MOID (NODE (t)) = z; } (void) a68_add_mode_to_pack (u, z, NO_TEXT, p); } else { get_mode_from_routine_pack (NEXT (p), u); get_mode_from_routine_pack (SUB (p), u); } } } /* Collect MODE from DECLARER. */ static MOID_T * get_mode_from_declarer (NODE_T *p) { if (p == NO_NODE) return NO_MOID; else { if (IS (p, DECLARER)) { if (MOID (p) != NO_MOID) return MOID (p); else return MOID (p) = get_mode_from_declarer (SUB (p)); } else { if (IS (p, VOID_SYMBOL)) { MOID (p) = M_VOID; return MOID (p); } else if (IS (p, LONGETY)) { if (a68_whether (p, LONGETY, INDICANT, STOP)) { int k = count_sizety (SUB (p)); MOID (p) = search_standard_mode (k, NEXT (p)); return MOID (p); } else { return NO_MOID; } } else if (IS (p, SHORTETY)) { if (a68_whether (p, SHORTETY, INDICANT, STOP)) { int k = count_sizety (SUB (p)); MOID (p) = search_standard_mode (k, NEXT (p)); return MOID (p); } else return NO_MOID; } else if (IS (p, INDICANT)) { MOID_T *q = search_standard_mode (0, p); if (q != NO_MOID) MOID (p) = q; else { /* Position of definition tells indicants apart. */ TAG_T *y = a68_find_tag_global (TABLE (p), INDICANT, NSYMBOL (p)); if (y == NO_TAG) a68_error ( p, "tag Z has not been declared properly", NSYMBOL (p)); else MOID (p) = a68_add_mode (&TOP_MOID (&A68_JOB), INDICANT, 0, NODE (y), NO_MOID, NO_PACK); } return MOID (p); } else if (IS_REF (p)) { MOID_T *new_one = get_mode_from_declarer (NEXT (p)); MOID (p) = a68_add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, p, new_one, NO_PACK); return MOID (p); } else if (IS_FLEX (p)) { MOID_T *new_one = get_mode_from_declarer (NEXT (p)); MOID (p) = a68_add_mode (&TOP_MOID (&A68_JOB), FLEX_SYMBOL, 0, p, new_one, NO_PACK); SLICE (MOID (p)) = SLICE (new_one); return MOID (p); } else if (IS (p, FORMAL_BOUNDS)) { MOID_T *new_one = get_mode_from_declarer (NEXT (p)); MOID (p) = add_row (&TOP_MOID (&A68_JOB), 1 + a68_count_formal_bounds (SUB (p)), new_one, p, false); return MOID (p); } else if (IS (p, BOUNDS)) { MOID_T *new_one = get_mode_from_declarer (NEXT (p)); MOID (p) = add_row (&TOP_MOID (&A68_JOB), count_bounds (SUB (p)), new_one, p, false); return MOID (p); } else if (IS (p, STRUCT_SYMBOL)) { PACK_T *u = NO_PACK; get_mode_from_struct_field (NEXT (p), &u); MOID (p) = a68_add_mode (&TOP_MOID (&A68_JOB), STRUCT_SYMBOL, a68_count_pack_members (u), p, NO_MOID, u); return MOID (p); } else if (IS (p, UNION_SYMBOL)) { PACK_T *u = NO_PACK; get_mode_from_union_pack (NEXT (p), &u); MOID (p) = a68_add_mode (&TOP_MOID (&A68_JOB), UNION_SYMBOL, a68_count_pack_members (u), p, NO_MOID, u); return MOID (p); } else if (IS (p, PROC_SYMBOL)) { NODE_T *save = p; PACK_T *u = NO_PACK; if (IS (NEXT (p), FORMAL_DECLARERS)) { get_mode_from_formal_pack (SUB_NEXT (p), &u); FORWARD (p); } MOID_T *new_one = get_mode_from_declarer (NEXT (p)); MOID (p) = a68_add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, a68_count_pack_members (u), save, new_one, u); MOID (save) = MOID (p); return MOID (p); } else return NO_MOID; } } } /* Collect MODEs from a routine-text header. */ static MOID_T * get_mode_from_routine_text (NODE_T *p) { PACK_T *u = NO_PACK; NODE_T *q = p; if (IS (p, PARAMETER_PACK)) { get_mode_from_routine_pack (SUB (p), &u); FORWARD (p); } MOID_T *n = get_mode_from_declarer (p); return a68_add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, a68_count_pack_members (u), q, n, u); } /* Collect modes from operator-plan. */ static MOID_T * get_mode_from_operator (NODE_T *p) { PACK_T *u = NO_PACK; NODE_T *save = p; if (IS (NEXT (p), FORMAL_DECLARERS)) { get_mode_from_formal_pack (SUB_NEXT (p), &u); FORWARD (p); } MOID_T *new_one = get_mode_from_declarer (NEXT (p)); MOID (p) = a68_add_mode (&TOP_MOID (&A68_JOB), PROC_SYMBOL, a68_count_pack_members (u), save, new_one, u); return MOID (p); } /* Collect mode from denotation. */ static void get_mode_from_denotation (NODE_T *p, int sizety) { if (p != NO_NODE) { if (IS (p, ROW_CHAR_DENOTATION)) { const char *s = NSYMBOL (p); size_t len = strlen (s); if (len == 1 || (len == 2 && s[0] == '\'') || (len == 8 && s[0] == '\'' && s[1] == '(' && s[2] == 'u') || (len == 12 && s[0] == '\'' && s[1] == '(' && s[2] == 'U')) { MOID (p) = M_CHAR; } else MOID (p) = M_ROW_CHAR; } else if (IS (p, TRUE_SYMBOL) || IS (p, FALSE_SYMBOL)) { MOID (p) = M_BOOL; } else if (IS (p, INT_DENOTATION)) { if (sizety == -2) MOID (p) = M_SHORT_SHORT_INT; else if (sizety == -1) MOID (p) = M_SHORT_INT; else if (sizety == 0) MOID (p) = M_INT; else if (sizety == 1) MOID (p) = M_LONG_INT; else if (sizety == 2) MOID (p) = M_LONG_LONG_INT; else MOID (p) = (sizety > 0 ? M_LONG_LONG_INT : M_INT); } else if (IS (p, REAL_DENOTATION)) { if (sizety == 0) MOID (p) = M_REAL; else if (sizety == 1) MOID (p) = M_LONG_REAL; else if (sizety == 2) MOID (p) = M_LONG_LONG_REAL; else MOID (p) = (sizety > 0 ? M_LONG_LONG_REAL : M_REAL); } else if (IS (p, BITS_DENOTATION)) { if (sizety == -2) MOID (p) = M_SHORT_SHORT_BITS; else if (sizety == -1) MOID (p) = M_SHORT_BITS; else if (sizety == 0) MOID (p) = M_BITS; else if (sizety == 1) MOID (p) = M_LONG_BITS; else if (sizety == 2) MOID (p) = M_LONG_LONG_BITS; else MOID (p) = (sizety > 0 ? M_LONG_LONG_BITS : M_BITS); } else if (IS (p, LONGETY) || IS (p, SHORTETY)) { get_mode_from_denotation (NEXT (p), count_sizety (SUB (p))); MOID (p) = MOID (NEXT (p)); } else if (IS (p, EMPTY_SYMBOL)) { MOID (p) = M_VOID; } } } /* Collect modes from the syntax tree. */ static void get_modes_from_tree (NODE_T *p, int attribute) { for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) { if (IS (q, VOID_SYMBOL)) MOID (q) = M_VOID; else if (IS (q, DECLARER)) { if (attribute == VARIABLE_DECLARATION) { MOID_T *new_one = get_mode_from_declarer (q); MOID (q) = a68_add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK); } else MOID (q) = get_mode_from_declarer (q); } else if (IS (q, ROUTINE_TEXT)) { MOID (q) = get_mode_from_routine_text (SUB (q)); } else if (IS (q, OPERATOR_PLAN)) { MOID (q) = get_mode_from_operator (SUB (q)); } else if (a68_is_one_of (q, LOC_SYMBOL, HEAP_SYMBOL, STOP)) { if (attribute == GENERATOR) { MOID_T *new_one = get_mode_from_declarer (NEXT (q)); MOID (NEXT (q)) = new_one; MOID (q) = a68_add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, NO_NODE, new_one, NO_PACK); } } else { if (attribute == DENOTATION) get_mode_from_denotation (q, 0); } } if (attribute != DENOTATION) { for (NODE_T *q = p; q != NO_NODE; FORWARD (q)) { if (SUB (q) != NO_NODE) get_modes_from_tree (SUB (q), ATTRIBUTE (q)); } } } //! @brief Collect modes from proc variables. static void get_mode_from_proc_variables (NODE_T *p) { if (p != NO_NODE) { if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) { get_mode_from_proc_variables (SUB (p)); get_mode_from_proc_variables (NEXT (p)); } else if (IS (p, QUALIFIER) || IS (p, PROC_SYMBOL) || IS (p, COMMA_SYMBOL)) { get_mode_from_proc_variables (NEXT (p)); } else if (IS (p, DEFINING_IDENTIFIER)) { MOID_T *new_one = MOID (NEXT_NEXT (p)); MOID (p) = a68_add_mode (&TOP_MOID (&A68_JOB), REF_SYMBOL, 0, p, new_one, NO_PACK); } } } /* Collect modes from proc variable declarations. */ static void get_mode_from_proc_var_declarations_tree (NODE_T *p) { for (; p != NO_NODE; FORWARD (p)) { get_mode_from_proc_var_declarations_tree (SUB (p)); if (IS (p, PROCEDURE_VARIABLE_DECLARATION)) get_mode_from_proc_variables (p); } } /* * Various routines to test modes. */ /* Whether a mode declaration refers to self or relates to void. This uses Lindsey's ying-yang algorithm. */ static bool is_well_formed (MOID_T *def, MOID_T *z, bool yin, bool yang, bool video) { if (z == NO_MOID) return false; else if (yin && yang) return z == M_VOID ? video : true; else if (z == M_VOID) return video; else if (IS (z, STANDARD)) return true; else if (IS (z, INDICANT)) { if (def == NO_MOID) { /* Check an applied indicant for relation to VOID. */ while (z != NO_MOID) z = EQUIVALENT (z); if (z == M_VOID) return video; else return true; } else { if (z == def || USE (z)) return yin && yang; else { USE (z) = true; bool wwf = is_well_formed (def, EQUIVALENT (z), yin, yang, video); USE (z) = false; return wwf; } } } else if (IS_REF (z)) return is_well_formed (def, SUB (z), true, yang, false); else if (IS (z, PROC_SYMBOL)) return PACK (z) != NO_PACK ? true : is_well_formed (def, SUB (z), true, yang, true); else if (IS_ROW (z)) return is_well_formed (def, SUB (z), yin, yang, false); else if (IS_FLEX (z)) return is_well_formed (def, SUB (z), yin, yang, false); else if (IS (z, STRUCT_SYMBOL)) { for (PACK_T *s = PACK (z); s != NO_PACK; FORWARD (s)) { if (!is_well_formed (def, MOID (s), yin, true, false)) return false; } return true; } else if (IS (z, UNION_SYMBOL)) { for (PACK_T *s = PACK (z); s != NO_PACK; FORWARD (s)) { if (!is_well_formed (def, MOID (s), yin, yang, true)) return false; } return true; } else { return false; } } /* Replace a mode by its equivalent mode (walk chain). */ static void resolve_eq_members (MOID_T *q) { resolve_equivalent (&SUB (q)); resolve_equivalent (&DEFLEXED (q)); resolve_equivalent (&MULTIPLE (q)); resolve_equivalent (&NAME (q)); resolve_equivalent (&SLICE (q)); resolve_equivalent (&TRIM (q)); resolve_equivalent (&ROWED (q)); for (PACK_T *p = PACK (q); p != NO_PACK; FORWARD (p)) resolve_equivalent (&MOID (p)); } /* Track equivalent tags. */ static void resolve_eq_tags (TAG_T *z) { for (; z != NO_TAG; FORWARD (z)) { if (MOID (z) != NO_MOID) resolve_equivalent (&MOID (z)); } } /* Bind modes in syntax tree. */ static void bind_modes (NODE_T *p) { for (; p != NO_NODE; FORWARD (p)) { resolve_equivalent (&MOID (p)); if (SUB (p) != NO_NODE && a68_is_new_lexical_level (p)) { TABLE_T *s = TABLE (SUB (p)); for (TAG_T *z = INDICANTS (s); z != NO_TAG; FORWARD (z)) { if (NODE (z) != NO_NODE) { resolve_equivalent (&MOID (NEXT_NEXT (NODE (z)))); MOID (z) = MOID (NEXT_NEXT (NODE (z))); MOID (NODE (z)) = MOID (z); } } } bind_modes (SUB (p)); } } /* Routines for calculating subordinates for selections, for instance selection from REF STRUCT (A) yields REF A fields and selection from [] STRUCT (A) yields [] A fields. */ /* Make name pack. Given a pack with modes: M1, M2, ... Build a pack with modes: REF M1, REF M2, ... */ static void make_name_pack (PACK_T *src, PACK_T **dst, MOID_T **p) { if (src != NO_PACK) { make_name_pack (NEXT (src), dst, p); MOID_T *z = a68_add_mode (p, REF_SYMBOL, 0, NO_NODE, MOID (src), NO_PACK); (void) a68_add_mode_to_pack (dst, z, TEXT (src), NODE (src)); } } /* Make flex multiple row pack. Given a pack with modes: M1, M2, ... Build a pack with modes: []M1, []M2, ... */ static void make_flex_multiple_row_pack (PACK_T *src, PACK_T **dst, MOID_T **p, int dim) { if (src != NO_PACK) { make_flex_multiple_row_pack (NEXT (src), dst, p, dim); MOID_T *z = add_row (p, dim, MOID (src), NO_NODE, false); z = a68_add_mode (p, FLEX_SYMBOL, 0, NO_NODE, z, NO_PACK); (void) a68_add_mode_to_pack (dst, z, TEXT (src), NODE (src)); } } /* Make name struct. */ static MOID_T * make_name_struct (MOID_T *m, MOID_T **p) { PACK_T *u = NO_PACK; make_name_pack (PACK (m), &u, p); return a68_add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u); } /* Make name row. */ static MOID_T * make_name_row (MOID_T *m, MOID_T **p) { if (SLICE (m) != NO_MOID) return a68_add_mode (p, REF_SYMBOL, 0, NO_NODE, SLICE (m), NO_PACK); else if (SUB (m) != NO_MOID) return a68_add_mode (p, REF_SYMBOL, 0, NO_NODE, SUB (m), NO_PACK); else /* weird, FLEX INT or so ... */ return NO_MOID; } /* Make multiple row pack. */ static void make_multiple_row_pack (PACK_T *src, PACK_T **dst, MOID_T **p, int dim) { if (src != NO_PACK) { make_multiple_row_pack (NEXT (src), dst, p, dim); (void) a68_add_mode_to_pack (dst, add_row (p, dim, MOID (src), NO_NODE, false), TEXT (src), NODE (src)); } } /* Make flex multiple struct. */ static MOID_T * make_flex_multiple_struct (MOID_T *m, MOID_T **p, int dim) { PACK_T *u = NO_PACK; make_flex_multiple_row_pack (PACK (m), &u, p, dim); return a68_add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u); } /* Make multiple struct. */ static MOID_T * make_multiple_struct (MOID_T *m, MOID_T **p, int dim) { PACK_T *u = NO_PACK; make_multiple_row_pack (PACK (m), &u, p, dim); return a68_add_mode (p, STRUCT_SYMBOL, DIM (m), NO_NODE, NO_MOID, u); } /* Whether mode has row. */ static bool is_mode_has_row (MOID_T *m) { if (IS (m, STRUCT_SYMBOL) || IS (m, UNION_SYMBOL)) { bool k = false; for (PACK_T *p = PACK (m); p != NO_PACK && k == false; FORWARD (p)) { HAS_ROWS (MOID (p)) = is_mode_has_row (MOID (p)); k |= (HAS_ROWS (MOID (p))); } return k; } else return (HAS_ROWS (m) || IS_ROW (m) || IS_FLEX (m)); } /* Compute derived modes. */ static void compute_derived_modes (MODULE_T *mod) { MOID_T *z; int len = 0, nlen = 1; /* UNION things. */ absorb_unions (TOP_MOID (mod)); contract_unions (TOP_MOID (mod)); /* The for-statement below prevents an endless loop. */ for (int k = 1; k <= 10 && len != nlen; k++) { /* Make deflexed modes. */ for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (SUB (z) != NO_MOID) { if (IS_REF_FLEX (z) && DEFLEXED (SUB_SUB (z)) != NO_MOID) DEFLEXED (z) = a68_add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB_SUB (z)), NO_PACK); else if (IS_REF (z) && DEFLEXED (SUB (z)) != NO_MOID) DEFLEXED (z) = a68_add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), DEFLEXED (SUB (z)), NO_PACK); else if (IS_ROW (z) && DEFLEXED (SUB (z)) != NO_MOID) DEFLEXED (z) = a68_add_mode (&TOP_MOID (mod), ROW_SYMBOL, DIM (z), NODE (z), DEFLEXED (SUB (z)), NO_PACK); else if (IS_FLEX (z) && DEFLEXED (SUB (z)) != NO_MOID) DEFLEXED (z) = DEFLEXED (SUB (z)); else if (IS_FLEX (z)) DEFLEXED (z) = SUB (z); else DEFLEXED (z) = z; } } /* Derived modes for stowed modes. */ for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (NAME (z) == NO_MOID && IS_REF (z)) { if (IS (SUB (z), STRUCT_SYMBOL)) NAME (z) = make_name_struct (SUB (z), &TOP_MOID (mod)); else if (IS_ROW (SUB (z))) NAME (z) = make_name_row (SUB (z), &TOP_MOID (mod)); else if (IS_FLEX (SUB (z)) && SUB_SUB (z) != NO_MOID) NAME (z) = make_name_row (SUB_SUB (z), &TOP_MOID (mod)); } if (MULTIPLE (z) != NO_MOID) ; else if (IS_REF (z)) { if (MULTIPLE (SUB (z)) != NO_MOID) MULTIPLE (z) = make_name_struct (MULTIPLE (SUB (z)), &TOP_MOID (mod)); } else if (IS_ROW (z)) { if (IS (SUB (z), STRUCT_SYMBOL)) MULTIPLE (z) = make_multiple_struct (SUB (z), &TOP_MOID (mod), DIM (z)); } } for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (TRIM (z) == NO_MOID && IS_FLEX (z)) TRIM (z) = SUB (z); if (TRIM (z) == NO_MOID && IS_REF_FLEX (z)) TRIM (z) = a68_add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), SUB_SUB (z), NO_PACK); } /* Fill out stuff for rows, f.i. inverse relations. */ for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS_ROW (z) && DIM (z) > 0 && SUB (z) != NO_MOID && !DERIVATE (z)) (void) add_row (&TOP_MOID (mod), DIM (z) + 1, SUB (z), NODE (z), true); else if (IS_REF (z) && IS (SUB (z), ROW_SYMBOL) && !DERIVATE (SUB (z))) { MOID_T *x = add_row (&TOP_MOID (mod), DIM (SUB (z)) + 1, SUB_SUB (z), NODE (SUB (z)), true); MOID_T *y = a68_add_mode (&TOP_MOID (mod), REF_SYMBOL, 0, NODE (z), x, NO_PACK); NAME (y) = z; } } for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS_ROW (z) && SLICE (z) != NO_MOID) ROWED (SLICE (z)) = z; if (IS_REF (z)) { MOID_T *y = SUB (z); if (SLICE (y) != NO_MOID && IS_ROW (SLICE (y)) && NAME (z) != NO_MOID) ROWED (NAME (z)) = z; } } bind_modes (TOP_NODE (mod)); for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS (z, INDICANT) && NODE (z) != NO_NODE) EQUIVALENT (z) = MOID (NODE (z)); } for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) resolve_eq_members (z); resolve_eq_tags (INDICANTS (A68_STANDENV)); resolve_eq_tags (IDENTIFIERS (A68_STANDENV)); resolve_eq_tags (OPERATORS (A68_STANDENV)); resolve_equivalent (&M_STRING); resolve_equivalent (&M_COMPLEX); resolve_equivalent (&M_LONG_COMPLEX); resolve_equivalent (&M_LONG_LONG_COMPLEX); resolve_equivalent (&M_SEMA); /* UNION members could be resolved. */ absorb_unions (TOP_MOID (mod)); contract_unions (TOP_MOID (mod)); /* FLEX INDICANT could be resolved. */ for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS_FLEX (z) && SUB (z) != NO_MOID) { if (SUB_SUB (z) != NO_MOID && IS (SUB_SUB (z), STRUCT_SYMBOL)) MULTIPLE (z) = make_flex_multiple_struct (SUB_SUB (z), &TOP_MOID (mod), DIM (SUB (z))); } } /* See what new known modes we have generated by resolving.. */ for (z = TOP_MOID (mod); z != STANDENV_MOID (&A68_JOB); FORWARD (z)) { MOID_T *v; for (v = NEXT (z); v != NO_MOID; FORWARD (v)) { if (a68_prove_moid_equivalence (z, v)) { EQUIVALENT (z) = v; EQUIVALENT (v) = NO_MOID; } } } /* Count the modes to check self consistency. */ len = nlen; for (nlen = 0, z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) nlen++; } gcc_assert (M_STRING == M_FLEX_ROW_CHAR); /* Find out what modes contain rows. */ for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) HAS_ROWS (z) = is_mode_has_row (z); /* Check flexible modes. */ for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS_FLEX (z) && !IS (SUB (z), ROW_SYMBOL)) a68_error (NODE (z), "M does not specify a well formed mode", z); } /* Check on fields in structured modes f.i. STRUCT (REAL x, INT n, REAL x) is wrong. */ for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS (z, STRUCT_SYMBOL) && EQUIVALENT (z) == NO_MOID) { PACK_T *s = PACK (z); for (; s != NO_PACK; FORWARD (s)) { bool x = true; for (PACK_T *t = NEXT (s); t != NO_PACK && x; FORWARD (t)) { if (TEXT (s) == TEXT (t)) { a68_error (NODE (z), "multiple declaration of field S"); while (NEXT (s) != NO_PACK && TEXT (NEXT (s)) == TEXT (t)) FORWARD (s); x = false; } } } } } /* Various union test. */ for (z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS (z, UNION_SYMBOL) && EQUIVALENT (z) == NO_MOID) { PACK_T *s = PACK (z); /* Discard unions with one member. */ if (a68_count_pack_members (s) == 1) a68_error (NODE (z), "M must have at least two components", z); /* Discard incestuous unions with firmly related modes. */ for (; s != NO_PACK; FORWARD (s)) { PACK_T *t; for (t = NEXT (s); t != NO_PACK; FORWARD (t)) { if (MOID (t) != MOID (s)) { if (a68_is_firm (MOID (s), MOID (t))) a68_error (NODE (z), "M has firmly related components", z); } } } /* Discard incestuous unions with firmly related subsets. */ for (s = PACK (z); s != NO_PACK; FORWARD (s)) { MOID_T *n = a68_depref_completely (MOID (s)); if (IS (n, UNION_SYMBOL) && a68_is_subset (n, z, NO_DEFLEXING)) a68_error (NODE (z), "M has firmly related subset M", z, n); } } } /* Wrap up and exit. */ a68_free_postulate_list (A68 (top_postulate), NO_POSTULATE); A68 (top_postulate) = NO_POSTULATE; } /* Make list of all modes in the program. */ void a68_make_moid_list (MODULE_T *mod) { bool cont = true; /* Collect modes from the syntax tree. */ reset_moid_tree (TOP_NODE (mod)); get_modes_from_tree (TOP_NODE (mod), STOP); get_mode_from_proc_var_declarations_tree (TOP_NODE (mod)); /* Connect indicants to their declarers. */ for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS (z, INDICANT)) { NODE_T *u = NODE (z); gcc_assert (NEXT (u) != NO_NODE); gcc_assert (NEXT_NEXT (u) != NO_NODE); gcc_assert (MOID (NEXT_NEXT (u)) != NO_MOID); EQUIVALENT (z) = MOID (NEXT_NEXT (u)); } } /* Checks on wrong declarations. */ for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) USE (z) = false; for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) { if (!is_well_formed (z, EQUIVALENT (z), false, false, true)) { a68_error (NODE (z), "M does not specify a well formed mode", z); cont = false; } } } for (MOID_T *z = TOP_MOID (mod); cont && z != NO_MOID; FORWARD (z)) { if (IS (z, INDICANT) && EQUIVALENT (z) != NO_MOID) ; else if (NODE (z) != NO_NODE) { if (!is_well_formed (NO_MOID, z, false, false, true)) a68_error (NODE (z), "M does not specify a well formed mode", z); } } for (MOID_T *z = TOP_MOID (mod); z != NO_MOID; FORWARD (z)) { if (USE (z)) gcc_unreachable (); } if (ERROR_COUNT (mod) != 0) return; compute_derived_modes (mod); a68_init_postulates (); }