📄 symbol.c
字号:
switch_types (st->left, from, to); switch_types (st->right, from, to);}/* This subroutine is called when a derived type is used in order to make the final determination about which version to use. The standard requires that a type be defined before it is 'used', but such types can appear in IMPLICIT statements before the actual definition. 'Using' in this context means declaring a variable to be that type or using the type constructor. If a type is used and the components haven't been defined, then we have to have a derived type in a parent unit. We find the node in the other namespace and point the symtree node in this namespace to that node. Further reference to this name point to the correct node. If we can't find the node in a parent namespace, then we have an error. This subroutine takes a pointer to a symbol node and returns a pointer to the translated node or NULL for an error. Usually there is no translation and we return the node we were passed. */gfc_symbol *gfc_use_derived (gfc_symbol * sym){ gfc_symbol *s; gfc_typespec *t; gfc_symtree *st; int i; if (sym->components != NULL) return sym; /* Already defined. */ if (sym->ns->parent == NULL) goto bad; if (gfc_find_symbol (sym->name, sym->ns->parent, 1, &s)) { gfc_error ("Symbol '%s' at %C is ambiguous", sym->name); return NULL; } if (s == NULL || s->attr.flavor != FL_DERIVED) goto bad; /* Get rid of symbol sym, translating all references to s. */ for (i = 0; i < GFC_LETTERS; i++) { t = &sym->ns->default_type[i]; if (t->derived == sym) t->derived = s; } st = gfc_find_symtree (sym->ns->sym_root, sym->name); st->n.sym = s; s->refs++; /* Unlink from list of modified symbols. */ gfc_commit_symbol (sym); switch_types (sym->ns->sym_root, sym, s); /* TODO: Also have to replace sym -> s in other lists like namelists, common lists and interface lists. */ gfc_free_symbol (sym); return s;bad: gfc_error ("Derived type '%s' at %C is being used before it is defined", sym->name); return NULL;}/* Given a derived type node and a component name, try to locate the component structure. Returns the NULL pointer if the component is not found or the components are private. */gfc_component *gfc_find_component (gfc_symbol * sym, const char *name){ gfc_component *p; if (name == NULL) return NULL; sym = gfc_use_derived (sym); if (sym == NULL) return NULL; for (p = sym->components; p; p = p->next) if (strcmp (p->name, name) == 0) break; if (p == NULL) gfc_error ("'%s' at %C is not a member of the '%s' structure", name, sym->name); else { if (sym->attr.use_assoc && sym->component_access == ACCESS_PRIVATE) { gfc_error ("Component '%s' at %C is a PRIVATE component of '%s'", name, sym->name); p = NULL; } } return p;}/* Given a symbol, free all of the component structures and everything they point to. */static voidfree_components (gfc_component * p){ gfc_component *q; for (; p; p = q) { q = p->next; gfc_free_array_spec (p->as); gfc_free_expr (p->initializer); gfc_free (p); }}/* Set component attributes from a standard symbol attribute structure. */voidgfc_set_component_attr (gfc_component * c, symbol_attribute * attr){ c->dimension = attr->dimension; c->pointer = attr->pointer;}/* Get a standard symbol attribute structure given the component structure. */voidgfc_get_component_attr (symbol_attribute * attr, gfc_component * c){ gfc_clear_attr (attr); attr->dimension = c->dimension; attr->pointer = c->pointer;}/******************** Statement label management ********************//* Free a single gfc_st_label structure, making sure the list is not messed up. This function is called only when some parse error occurs. */voidgfc_free_st_label (gfc_st_label * label){ if (label == NULL) return; if (label->prev) label->prev->next = label->next; if (label->next) label->next->prev = label->prev; if (gfc_current_ns->st_labels == label) gfc_current_ns->st_labels = label->next; if (label->format != NULL) gfc_free_expr (label->format); gfc_free (label);}/* Free a whole list of gfc_st_label structures. */static voidfree_st_labels (gfc_st_label * l1){ gfc_st_label *l2; for (; l1; l1 = l2) { l2 = l1->next; if (l1->format != NULL) gfc_free_expr (l1->format); gfc_free (l1); }}/* Given a label number, search for and return a pointer to the label structure, creating it if it does not exist. */gfc_st_label *gfc_get_st_label (int labelno){ gfc_st_label *lp; /* First see if the label is already in this namespace. */ for (lp = gfc_current_ns->st_labels; lp; lp = lp->next) if (lp->value == labelno) break; if (lp != NULL) return lp; lp = gfc_getmem (sizeof (gfc_st_label)); lp->value = labelno; lp->defined = ST_LABEL_UNKNOWN; lp->referenced = ST_LABEL_UNKNOWN; lp->prev = NULL; lp->next = gfc_current_ns->st_labels; if (gfc_current_ns->st_labels) gfc_current_ns->st_labels->prev = lp; gfc_current_ns->st_labels = lp; return lp;}/* Called when a statement with a statement label is about to be accepted. We add the label to the list of the current namespace, making sure it hasn't been defined previously and referenced correctly. */voidgfc_define_st_label (gfc_st_label * lp, gfc_sl_type type, locus * label_locus){ int labelno; labelno = lp->value; if (lp->defined != ST_LABEL_UNKNOWN) gfc_error ("Duplicate statement label %d at %L and %L", labelno, &lp->where, label_locus); else { lp->where = *label_locus; switch (type) { case ST_LABEL_FORMAT: if (lp->referenced == ST_LABEL_TARGET) gfc_error ("Label %d at %C already referenced as branch target", labelno); else lp->defined = ST_LABEL_FORMAT; break; case ST_LABEL_TARGET: if (lp->referenced == ST_LABEL_FORMAT) gfc_error ("Label %d at %C already referenced as a format label", labelno); else lp->defined = ST_LABEL_TARGET; break; default: lp->defined = ST_LABEL_BAD_TARGET; lp->referenced = ST_LABEL_BAD_TARGET; } }}/* Reference a label. Given a label and its type, see if that reference is consistent with what is known about that label, updating the unknown state. Returns FAILURE if something goes wrong. */trygfc_reference_st_label (gfc_st_label * lp, gfc_sl_type type){ gfc_sl_type label_type; int labelno; try rc; if (lp == NULL) return SUCCESS; labelno = lp->value; if (lp->defined != ST_LABEL_UNKNOWN) label_type = lp->defined; else { label_type = lp->referenced; lp->where = gfc_current_locus; } if (label_type == ST_LABEL_FORMAT && type == ST_LABEL_TARGET) { gfc_error ("Label %d at %C previously used as a FORMAT label", labelno); rc = FAILURE; goto done; } if ((label_type == ST_LABEL_TARGET || label_type == ST_LABEL_BAD_TARGET) && type == ST_LABEL_FORMAT) { gfc_error ("Label %d at %C previously used as branch target", labelno); rc = FAILURE; goto done; } lp->referenced = type; rc = SUCCESS;done: return rc;}/************** Symbol table management subroutines ****************//* Basic details: Fortran 95 requires a potentially unlimited number of distinct namespaces when compiling a program unit. This case occurs during a compilation of internal subprograms because all of the internal subprograms must be read before we can start generating code for the host. Given the tricky nature of the Fortran grammar, we must be able to undo changes made to a symbol table if the current interpretation of a statement is found to be incorrect. Whenever a symbol is looked up, we make a copy of it and link to it. All of these symbols are kept in a singly linked list so that we can commit or undo the changes at a later time. A symtree may point to a symbol node outside of its namespace. In this case, that symbol has been used as a host associated variable at some previous time. *//* Allocate a new namespace structure. Copies the implicit types from PARENT if PARENT_TYPES is set. */gfc_namespace *gfc_get_namespace (gfc_namespace * parent, int parent_types){ gfc_namespace *ns; gfc_typespec *ts; gfc_intrinsic_op in; int i; ns = gfc_getmem (sizeof (gfc_namespace)); ns->sym_root = NULL; ns->uop_root = NULL; ns->default_access = ACCESS_UNKNOWN; ns->parent = parent; for (in = GFC_INTRINSIC_BEGIN; in != GFC_INTRINSIC_END; in++) ns->operator_access[in] = ACCESS_UNKNOWN; /* Initialize default implicit types. */ for (i = 'a'; i <= 'z'; i++) { ns->set_flag[i - 'a'] = 0; ts = &ns->default_type[i - 'a']; if (parent_types && ns->parent != NULL) { /* Copy parent settings */ *ts = ns->parent->default_type[i - 'a']; continue; } if (gfc_option.flag_implicit_none != 0) { gfc_clear_ts (ts); continue; } if ('i' <= i && i <= 'n') { ts->type = BT_INTEGER; ts->kind = gfc_default_integer_kind; } else { ts->type = BT_REAL; ts->kind = gfc_default_real_kind; } } ns->refs = 1; return ns;}/* Comparison function for symtree nodes. */static intcompare_symtree (void * _st1, void * _st2){ gfc_symtree *st1, *st2; st1 = (gfc_symtree *) _st1; st2 = (gfc_symtree *) _st2; return strcmp (st1->name, st2->name);}/* Allocate a new symtree node and associate it with the new symbol. */gfc_symtree *gfc_new_symtree (gfc_symtree ** root, const char *name){ gfc_symtree *st; st = gfc_getmem (sizeof (gfc_symtree)); st->name = gfc_get_string (name); gfc_insert_bbt (root, st, compare_symtree); return st;}/* Delete a symbol from the tree. Does not free the symbol itself! */static voiddelete_symtree (gfc_symtree ** root, const char *name){ gfc_symtree st, *st0; st0 = gfc_find_symtree (*root, name); st.name = gfc_get_string (name); gfc_delete_bbt (root, &st, compare_symtree); gfc_free (st0);}/* Given a root symtree node and a name, try to find the symbol within the namespace. Returns NULL if the symbol is not found. */gfc_symtree *gfc_find_symtree (gfc_symtree * st, const char *name){ int c; while (st != NULL) { c = strcmp (name, st->name); if (c == 0) return st; st = (c < 0) ? st->left : st->right; } return NULL;}/* Given a name find a user operator node, creating it if it doesn't exist. These are much simpler than symbols because they can't be ambiguous with one another. */gfc_user_op *gfc_get_uop (const char *name){ gfc_user_op *uop; gfc_symtree *st; st = gfc_find_symtree (gfc_current_ns->uop_root, name); if (st != NULL) return st->n.uop; st = gfc_new_symtree (&gfc_current_ns->uop_root, name); uop = st->n.uop = gfc_getmem (sizeof (gfc_user_op)); uop->name = gfc_get_string (name); uop->access = ACCESS_UNKNOWN; uop->ns = gfc_current_ns; return uop;}/* Given a name find the user operator node. Returns NULL if it does not exist. */gfc_user_op *gfc_find_uop (const char *name, gfc_namespace * ns){ gfc_symtree *st; if (ns == NULL) ns = gfc_current_ns; st = gfc_find_symtree (ns->uop_root, name); return (st == NULL) ? NULL : st->n.uop;}/* Remove a gfc_symbol structure and everything it points to. */voidgfc_free_symbol (gfc_symbol * sym){ if (sym == NULL) return; gfc_free_array_spec (sym->as); free_components (sym->components); gfc_free_expr (sym->value); gfc_free_namelist (sym->namelist); gfc_free_namespace (sym->formal_ns); gfc_free_interface (sym->generic); gfc_free_formal_arglist (sym->formal); gfc_free (sym);}/* Allocate and initialize a new symbol node. */gfc_symbol *gfc_new_symbol (const char *name, gfc_namespace * ns){ gfc_symbol *p; p = gfc_getmem (sizeof (gfc_symbol)); gfc_clear_ts (&p->ts); gfc_clear_attr (&p->attr); p->ns = ns; p->declared_at = gfc_current_locus; if (strlen (name) > GFC_MAX_SYMBOL_LEN) gfc_internal_error ("new_symbol(): Symbol name too long"); p->name = gfc_get_string (name); return p;}/* Generate an error if a symbol is ambiguous. */static voidambiguous_symbol (const char *name, gfc_symtree * st){ if (st->n.sym->module) gfc_error ("Name '%s' at %C is an ambiguous reference to '%s' " "from module '%s'", name, st->n.sym->name, st->n.sym->module); else gfc_error ("Name '%s' at %C is an ambiguous reference to '%s' " "from current program unit", name, st->n.sym->name);}/* Search for a symtree starting in the current namespace, resorting to any parent namespaces if requested by a nonzero parent_flag. Returns nonzero if the name is ambiguous. */intgfc_find_sym_tree (const char *name, gfc_namespace * ns, int parent_flag, gfc_symtree ** result){ gfc_symtree *st; if (ns == NULL) ns = gfc_current_ns; do { st = gfc_find_symtree (ns->sym_root, name); if (st != NULL) { *result = st; if (st->ambiguous) { ambiguous_symbol (name, st); return 1; } return 0; } if (!parent_flag) break; ns = ns->parent; } while (ns != NULL); *result = NULL; return 0;}/* Same, but returns the symbol instead. */intgfc_find_symbol (const char *name, gfc_namespace * ns, int parent_flag, gfc_symbol ** result){ gfc_symtree *st; int i; i = gfc_find_sym_tree (name, ns, parent_flag, &st); if (st == NULL) *result = NULL; else *result = st->n.sym; return i;}/* Save symbol with the information necessary to back it out. */static voidsave_symbol_data (gfc_symbol * sym){ if (sym->new || sym->old_symbol != NULL) return; sym->old_symbol = gfc_getmem (sizeof (gfc_symbol)); *(sym->old_symbol) = *sym; sym->tlink = changed_syms; changed_syms = sym;}/* Given a name, find a symbol, or create it if it does not exist yet in the current namespace. If the symbol is found we make sure that it's OK.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -