📄 pgsymtab.c
字号:
} } } }} /* Returns TRUE unless block is SAVED by any module, or declared by the actual main program or in a BLOCK DATA subprogram. */PRIVATE intblock_is_volatile(clist,main_module) ComListHeader *clist; Gsymtab *main_module;{ int t; while(clist != NULL) { if( clist->saved || (t=datatype_of(clist->module->type)) == type_BLOCK_DATA || (t == type_PROGRAM && clist->module == main_module)) { return FALSE; } clist = clist->next; } return TRUE;} /* If block declared by module, returns pointer to the comlist header which describes it. Otherwise returns NULL. */PRIVATE ComListHeader *com_declared_by(comblock,module) Gsymtab *comblock,*module;{ ComListHeader *clist=comblock->info.comlist; while(clist != NULL) { if(clist->module == module) { if(clist->saved) { com_tree_error = TRUE; /* not so, but causes bailout */ } return clist; } clist = clist->next; } return NULL;} /* Checks whether common block can become undefined between activations of some module that declares it. Should only be done for blocks that are volatile, i.e. that are not SAVED or declared in main or block_data. Rules used are: (1) Block is declared in two subtrees whose roots are called by a given module, and not in the given module itself or above. (2) Block is declared and elements accessed in a module called by a given module, and not declared in the module itself or above. (Module that declares it but does not access elements, can be holding the block active for its children.) Since Rule 2 is likely to be wrong often due to Ftnchek's lack of knowledge about whether a routine is invoked more than once, it is suppressed for now. */PRIVATE ComListHeader *com_tree_check(comblock,module,level) Gsymtab *comblock,*module; int level;{ ComListHeader *clist; /* The following only protects against recursion. It is not a full-fledged cycle detector just a stopper. */ if(level > numvisited) { fprintf(list_fd, "\nWarning: Call tree has a cycle containing module %s\n", module->name); com_tree_error = TRUE; return NULL; } /* If this module declares the block, return its clist */ if( (clist=com_declared_by(comblock,module)) != NULL) {#ifdef DEBUG_SAVE fprintf(list_fd,"\n%s declared by %s",comblock->name,module->name);#endif return clist; } else { /* Otherwise see if it is declared in subtree */ int any_child_declares_it; ComListHeader *declaring_clist, *this_clist; ChildList *child_list; any_child_declares_it=FALSE; declaring_clist=NULL; /* Scan list of children */ child_list = (module->internal_entry?module->link.module:module) ->link.child_list; while(child_list != NULL) { this_clist = com_tree_check(comblock,child_list->child,level+1); /* Error was detected below: bail out */ if(com_tree_error) { return NULL; } else if(this_clist != NULL) { /* Subtree contains the block */ if(any_child_declares_it /* Rule 1 */#ifdef COMTREE_RULE_2 || (this_clist->any_used || this_clist->any_set) /* Rule 2 */#endif ){ fprintf(list_fd, "\nWarning: Common block %s may become undefined between activations", comblock->name); fprintf(list_fd,"\n "); com_error_locate(this_clist); if(declaring_clist != NULL && declaring_clist != this_clist) { fprintf(list_fd,"\n "); com_error_locate(declaring_clist); } fprintf(list_fd,"\n "); fprintf(list_fd, "during activation of module %s", module->name); com_tree_error = TRUE; return NULL; } else { any_child_declares_it = TRUE; declaring_clist = this_clist; } } child_list = child_list->next; } /* If any subtree declares it, say so */ return declaring_clist; }} /* Depth-first search of call tree */PRIVATE voidvisit_child(gsymt,level) Gsymtab *gsymt; int level;{ static char fmt[]="%000s"; /* Variable format for indenting names */ ChildList *child_list; if(print_call_tree) { fprintf(list_fd,"\n"); if(level > 0) { sprintf(fmt,"%%%ds",level*4); /* indent 4 spaces per nesting level */ fprintf(list_fd,fmt,""); } fprintf(list_fd,"%s",gsymt->name); } /* Visit its unvisited children. Note that children of internal entry are taken as those of its superior module. */ child_list = (gsymt->internal_entry?gsymt->link.module:gsymt) ->link.child_list; /* If already visited, do not visit its children, but give note to reader if it has some. */ if(gsymt->visited) { if(print_call_tree && child_list != NULL) fprintf(list_fd," (see above)"); } else { /* Mark node as visited */ gsymt->visited = TRUE; /* Record that containing module is visited via this entry point*/ if(gsymt->internal_entry) gsymt->link.module->visited_somewhere = TRUE; else gsymt->visited_somewhere = TRUE; ++level; /* move to next level */ while(child_list != NULL) { visit_child(child_list->child,level); child_list = child_list->next; } }}/*** visit_child_reflistSame as visit_child, except it does a breadth-first search of the calltree, and prints the results in the form of a who-calls-who list.Contributed by: Gerome Emmanuel : Esial Troisieme annee Projet commun Esial / Ecole des mines INERIS E-mail: gerome@mines.u-nancy.frDate received: 20-APR-1993Modified slightly to make it compatible as alternative to call-tree andto make output format consistent.***/PRIVATE voidvisit_child_reflist(gsymt) Gsymtab *gsymt;{ ChildList *child_list; child_list = (gsymt->internal_entry?gsymt->link.module:gsymt) ->link.child_list; /* If already visited, do not visit its children, but give note to reader if it has some. */ if(!gsymt->visited) { /* Mark node as visited */ gsymt->visited = TRUE; /* Record that containing module is visited via this entry point*/ if(gsymt->internal_entry) gsymt->link.module->visited_somewhere = TRUE; else gsymt->visited_somewhere = TRUE; if(print_ref_list) /* Print callees neatly if desired */ {#ifdef DYNAMIC_TABLES /* tables will be mallocked at runtime */ Gsymtab **gsymlist;#else Gsymtab *gsymlist[GLOBSYMTABSZ];#endif ChildList *child_list2; unsigned numcalls;#ifdef DYNAMIC_TABLES if( (gsymlist=(Gsymtab **)SN_calloc(glob_symtab_top,sizeof(Gsymtab *))) == (Gsymtab **)NULL) { oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM, "Cannot malloc space for reference list"); }#endif fprintf(list_fd,"\n%s calls:",gsymt->name); numcalls = 0; child_list2 = child_list; while(child_list2 != NULL) { gsymlist[numcalls++] = child_list2->child; child_list2 = child_list2->next; } if(numcalls == (unsigned)0) fprintf(list_fd," none"); else { fprintf(list_fd,"\n"); print_modules(numcalls,gsymlist); }#ifdef DYNAMIC_TABLES (void) cfree(gsymlist);#endif } while(child_list != NULL) { visit_child_reflist(child_list->child); child_list = child_list->next; } }}PRIVATE voidprint_crossrefs(){#ifdef DYNAMIC_TABLES /* tables will be mallocked at runtime */ Gsymtab **gsymlist, **modulelist;#else Gsymtab *gsymlist[GLOBSYMTABSZ], *modulelist[GLOBSYMTABSZ];#endif ArgListHeader *args; int i,numentries; unsigned numcalls;#ifdef DYNAMIC_TABLES if( (gsymlist=(Gsymtab **)SN_calloc(glob_symtab_top,sizeof(Gsymtab *))) == (Gsymtab **)NULL || (modulelist=(Gsymtab **)SN_calloc(glob_symtab_top,sizeof(Gsymtab *))) == (Gsymtab **)NULL) { oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM, "Cannot malloc space for crossref list"); }#endif /* Gather up all relevant subprograms */ for(i=0,numentries=0; i<glob_symtab_top; i++) { if(storage_class_of(glob_symtab[i].type) == class_SUBPROGRAM && (glob_symtab[i].visited || !glob_symtab[i].library_module)) { gsymlist[numentries++] = &glob_symtab[i]; } } if(numentries > 0) { fprintf(list_fd,"\n\n Cross-reference list:\n"); /* Sort the subprograms */ sort_gsymbols(gsymlist,numentries); /* Print their callers */ for(i=0; i<numentries; i++) { fprintf(list_fd,"\n%s",gsymlist[i]->name); numcalls=0; args = gsymlist[i]->info.arglist; while(args != NULL) { /* Gather up callers */ if(!args->is_defn) { /* (eliminate duplicates) */ if(numcalls==(unsigned) 0 || args->module != modulelist[numcalls-1]) modulelist[numcalls++] = args->module; } args = args->next; } if(numcalls == (unsigned) 0) fprintf(list_fd," not called"); else { fprintf(list_fd," called by:\n"); sort_gsymbols(modulelist,numcalls); /* Sort the callers */ print_modules(numcalls,modulelist); } } fprintf(list_fd,"\n"); }#ifdef DYNAMIC_TABLES (void) cfree(gsymlist); (void) cfree(modulelist);#endif} /* Topological sort of the call tree. Based closely on algorithm on page 314 of Horowitz and Sahni, Fundamentals of Data Structures. Returns TRUE if successful, FALSE if failed due to a cycle being detected. */PRIVATE void print_cycle_nodes(); /* Routine for error diagnostics */PRIVATE inttoposort(gsymt,nsym) Gsymtab gsymt[]; int nsym;{ int i,num_nodes; unsigned node_count; ChildList *child_list;#ifdef DYNAMIC_TABLES /* tables will be mallocked at runtime */ int *parent_count; Gsymtab **node_list;#else int parent_count[GLOBSYMTABSZ]; Gsymtab *node_list[GLOBSYMTABSZ];#endif#ifdef DYNAMIC_TABLES if( (parent_count=(int *)SN_calloc(glob_symtab_top,sizeof(int))) == (int *)NULL || (node_list=(Gsymtab **)SN_calloc(glob_symtab_top,sizeof(Gsymtab *))) == (Gsymtab **)NULL) { oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM, "Cannot malloc space for module sort"); }#endif /* Initialize array of links/counts */ for(i=0; i<nsym; i++) parent_count[i] = 0; /* In-order of module as node */ /* Traverse child lists, incrementing their parent counts. */ for(i=0,num_nodes=0; i<nsym; i++) { if(gsymt[i].visited_somewhere) { /* skip entry pts and com blocks */ ++num_nodes; child_list = gsymt[i].link.child_list; while(child_list != NULL) { ++parent_count[child_list->child - gsymt]; /* index into table */ child_list = child_list->next; } } } { /* Start of the sort */ int top=0; int j,k; for(i=0; i<nsym; i++) { if(gsymt[i].visited_somewhere && parent_count[i] == 0) { parent_count[i] = top; /* Link now-parentless module into stack */ top = i+1; } } for(i=0,node_count=0; i<num_nodes; i++) { if(top == 0) { if(print_topo_sort) { fprintf(list_fd,"\nCall tree has a cycle"); print_cycle_nodes(gsymt,nsym,node_list,node_count,parent_count); } break; } j = top-1; top = parent_count[j]; /* Recover the link */ /* Print the next module */ if(print_topo_sort) { node_list[node_count++] = &gsymt[j]; parent_count[j] = -1; } /* Decrease parent count of its children */ child_list = gsymt[j].link.child_list; while(child_list != NULL) { k = child_list->child - gsymt; if(--parent_count[k] == 0) { /* Now parentless? Stack it*/ parent_count[k] = top; top = k+1; } child_list = child_list->next; } } }/*end sort*/ if(print_topo_sort && node_count > 0) { fprintf(list_fd,"\nList of called modules in prerequisite order:\n"); print_modules(node_count,node_list); fprintf(list_fd,"\n"); }#ifdef DYNAMIC_TABLES (void) cfree(parent_count); (void) cfree(node_list);#endif return (node_count==num_nodes); /* Success = TRUE */} /* Traces back to find nodes not listed in topological sort. They are the cycle nodes and their descendants. */PRIVATE voidprint_cycle_nodes(gsymt,nsym,node_list,node_count,parent_count) Gsymtab gsymt[]; int nsym; Gsymtab *node_list[]; unsigned node_count; int parent_count[];{ int i; int k=node_count; for(i=0; i<nsym; i++) { if(gsymt[i].visited_somewhere) { if(parent_count[i] != -1) /* Not tagged */ node_list[k++] = &gsymt[i]; } } if(k > node_count) fprintf(list_fd," containing some of the following modules:\n"); print_modules(k-node_count,node_list+node_count);} /* Insertion sort of child list. Also removes duplicates which can be introduced via multiple defns or via project files. */PRIVATE voidsort_child_list(child_list) ChildList *child_list;{ ChildList *front,*prev,*next; Gsymtab *temp; prev = NULL; while(child_list != NULL) { /* Scan thru list for lexicographically lowest name */ front=child_list; for(next=child_list->next; next != NULL; next = next->next) { if(strcmp(front->child->name,next->child->name) > 0) { front = next; } } /* Swap child pointers so front is first */ if(front != child_list) { temp = front->child; front->child = child_list->child; child_list->child = temp; } /* If duplicate, remove from list */ if(prev != NULL && prev->child == child_list->child) prev->next = child_list->next; else prev = child_list; child_list = child_list->next; }}PRIVATE voidsort_gsymbols ( glist,n ) /* bubble sort, same as sort_symbols */ Gsymtab *glist[]; int n;{ int i,j,swaps; for (i=0; i<n; i++ ){ swaps = 0; for (j=n-1; j>=i+1; j--){ if ((strcmp (glist[j-1]->name, glist[j]->name)) >0) { swap_gsymptrs(&glist[j-1], &glist[j] ); swaps++; } } if (swaps == 0) break; }}PRIVATE voidswap_gsymptrs (x_ptr, y_ptr) /* swap pointers */ Gsymtab **x_ptr,**y_ptr;{ Gsymtab *temp = *x_ptr; *x_ptr = *y_ptr; *y_ptr = temp;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -