home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
fchek284.zip
/
plsymtab.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-13
|
60KB
|
2,294 lines
/* plsymtab.c:
Routines associated with printing of local symbol table info
Copyright (C) 1993 by Robert K. Moniot.
This program is free software. Permission is granted to
modify it and/or redistribute it, retaining this notice.
No guarantees accompany this software.
Shared functions defined:
debug_symtabs() Prints debugging info about symbol tables.
print_loc_symbols(curmodhash) Prints local symtab info.
Private functions defined:
has_nonalnum() True if string has non-alphanumeric char
sort_symbols() Sorts the list of names of a given category.
swap_symptrs() Swaps a pair of pointers.
check_flags() Outputs messages about used-before-set etc.
check_mixed_common() checks common for nonportable mixed type
print_symbols(sym_list,n,do_types) Prints symbol lists.
print_variables(sym_list,n) Prints variable symbol table
find_sixclashes() Finds variables with the same first 6 chars.
identify_module(mod_name) Prints module name and file name.
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "ftnchek.h"
#define PLSYMTAB
#include "symtab.h"
PRIVATE int
count_undeclared_variables(), find_sixclashes(), has_nonalnum(),
make_sym_list(), print_list_name(), print_list_name(), print_symbols(),
print_type_name(), print_var_type(), print_variables(), select_arguments(),
select_common_blocks(), select_commons(), select_externals_by_name(),
select_externals_by_type(), select_intrinsics_by_name(),
select_intrinsics_by_type(), select_locals(), select_namelists(),
select_parameters(), select_statement_functions(), sf3_internal_name();
PRIVATE void
append_char_to_fragment(), append_expr_text_to_fragment(),
append_string_to_fragment(), check_flags(), check_mixed_common(),
identify_module(), make_declarations(), maybe_print_module_header(),
new_fragment(), print_arg_array(), print_blanks(), print_com_array(),
print_common_decls(), print_declaration_class(), print_empty_comment_line(),
print_equivalence_decls(), print_list_decls(), print_one_list_decls(),
print_parameter_statement(), print_selected_declarations(), print_tokenlist(),
sort_positions(), sort_symbols(), swap_symptrs();
PRIVATE void
sort_positions(sp,n) /* sort a given list by sequence num instead of name */
Lsymtab *sp[];
int n;
{
int i,j,swaps;
for (i = 0; i < n; i++)
{
swaps = 0;
for (j = n-1; j >= i+1; j--)
{
if ( sp[j-1]->info.param->seq_num > sp[j]->info.param->seq_num )
{
swap_symptrs(&sp[j-1], &sp[j]);
swaps ++;
}
}
if(swaps == 0)
break;
}
}
PRIVATE void
sort_symbols(sp,n) /* sorts a given list */
Lsymtab *sp[];
int n;
{
int i,j,swaps;
for(i=0;i<n;i++) {
swaps = 0;
for(j=n-1;j>=i+1;j--) {
if((strcmp(sp[j-1]->name, sp[j]->name)) > 0) {
swap_symptrs(&sp[j-1], &sp[j]);
swaps ++;
}
}
if(swaps == 0) break;
}
}
PRIVATE void /* swaps two pointers */
swap_symptrs(x_ptr,y_ptr)
Lsymtab **x_ptr,**y_ptr;
{
Lsymtab *temp = *x_ptr;
*x_ptr = *y_ptr;
*y_ptr = temp;
}
/* Routine to print module name and file name just once in standard
format is shared by print_loc_symbols, check_mixed_common and check_flags*/
PRIVATE int any_warnings;
PRIVATE void
identify_module(mod_name)
char *mod_name;
{
if(do_symtab) {
(void)fprintf(list_fd,"\nWarning: ");
}
else {
if(any_warnings++ == 0) { /* 1st message of this module? */
if(novice_help) { /* Old-style format */
(void)fprintf(list_fd,
"\nWarning in module %s file %s:",
mod_name,current_filename);
}
else { /* Lint-style format */
(void)fprintf(list_fd,
"\n\"%s\" module %s: Warning:",
current_filename,mod_name);
}
}
(void)fprintf(list_fd,"\n "); /* Details go indented on next line */
}
++warning_count; /* Count these warnings too */
}
void
print_loc_symbols(curmodhash)
int curmodhash; /* hash entry of current module */
{
#ifdef DYNAMIC_TABLES /* tables will be mallocked at runtime */
static Lsymtab **sym_list=(Lsymtab **)NULL;
#else
Lsymtab *sym_list[LOCSYMTABSZ]; /* temp. list of symtab entries to print */
#endif
int mod_type, /* datatype of this module */
this_is_a_function; /* flag for treating funcs specially */
Lsymtab *module; /* entry of current module in symtab */
char *mod_name; /* module name */
int
com_vars_modified=0, /* count of common variables which are set */
args_modified=0, /* count of arguments which are set */
imps=0, /* count of implicitly declared identifiers */
numentries; /* count of entry points of module */
if (dcl_fd == (FILE*)NULL)
dcl_fd = stdout;
#ifdef DYNAMIC_TABLES
if(sym_list == (Lsymtab **)NULL) { /* Initialize if not done before */
if( (sym_list=(Lsymtab **)calloc(LOCSYMTABSZ,sizeof(Lsymtab *)))
== (Lsymtab **)NULL) {
oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM,
"Cannot malloc space for local symbol list");
}
}
#endif
any_warnings=0; /* for identify_module(mod_name); */
/* Keep track of statement counts
for -resource */
tot_exec_stmt_count += exec_stmt_count;
if(exec_stmt_count > max_exec_stmt_count)
max_exec_stmt_count = exec_stmt_count;
/* Keep track of symbol table and string usage */
if(loc_symtab_top > max_loc_symtab) {
max_loc_symtab = loc_symtab_top;
}
if(loc_str_top + extra_locstrspace > max_loc_strings) {
max_loc_strings = loc_str_top + extra_locstrspace;
}
if(srctextspace_top + extra_srctextspace > max_srctextspace) {
max_srctextspace = srctextspace_top + extra_srctextspace;
}
if(token_head_space_top + extra_tokheadspace > max_tokenlists) {
max_tokenlists=token_head_space_top + extra_tokheadspace;
}
if(param_info_space_top + extra_paraminfospace > max_paraminfo) {
max_paraminfo=param_info_space_top + extra_paraminfospace;
}
if(token_space_top + extra_tokspace > max_token_space) {
max_token_space = token_space_top + extra_tokspace;
}
if(ptrspace_top + extra_ptrspace > max_ptrspace) {
max_ptrspace = ptrspace_top + extra_ptrspace;
}
/* Global symbols only increase in number */
max_glob_symtab = glob_symtab_top;
/* Set up name & type, and see what kind of module it is */
module = hashtab[curmodhash].loc_symtab;
mod_name = module->name;
mod_type = get_type(module);
if( mod_type != type_PROGRAM
&& mod_type != type_SUBROUTINE
&& mod_type != type_COMMON_BLOCK
&& mod_type != type_BLOCK_DATA )
this_is_a_function = TRUE;
else
this_is_a_function = FALSE;
/* Print name & type of the module */
if(do_symtab) {
int i;
for(i=0,numentries=0;i<loc_symtab_top;i++) {
if(loc_symtab[i].entry_point)
sym_list[numentries++] = &loc_symtab[i];
}
if(numentries > 1) {
sort_symbols(sym_list,numentries);
}
(void)fprintf(list_fd,"\n\nModule %s:",mod_name);
if( this_is_a_function ) (void)fprintf(list_fd," func:");
(void)fprintf(list_fd," %4s",type_name[mod_type]);
/* Print a * next to non-declared function name */
if(datatype_of(module->type) == type_UNDECL ) {
(void)fprintf(list_fd,"*");
imps++;
}
(void)fprintf(list_fd,"\n");
/* Print Entry Points (skip if only one,
since it is same as module name) */
if(do_symtab && numentries > 1) {
(void)fprintf(list_fd,"\nEntry Points\n");
(void) print_symbols(list_fd,sym_list,numentries,FALSE);
}
/* End of printing module name and entry points */
}/*if(do_symtab)*/
/* Print the externals */
if(do_symtab) {
int i,n;
for(i=0,n=0;i<loc_symtab_top;i++) {
if(storage_class_of(loc_symtab[i].type) == class_SUBPROGRAM) {
sym_list[n++] = &loc_symtab[i];
}
}
if(n != 0) {
sort_symbols(sym_list,n);
if (do_symtab)
{
(void)fprintf(list_fd,"\nExternal subprograms referenced:\n");
imps += print_symbols(list_fd,sym_list,n,TRUE);
}
}
}/*if(do_symtab)*/
/* Print list of statement functions */
if(do_symtab) {
int i,n;
for(i=0,n=0;i<loc_symtab_top;i++) {
if(storage_class_of(loc_symtab[i].type) == class_STMT_FUNCTION){
sym_list[n++] = &loc_symtab[i];
}
}
if(n != 0) {
sort_symbols(sym_list,n);
(void)fprintf(list_fd,"\nStatement functions defined:\n");
imps += print_symbols(list_fd,sym_list,n,TRUE);
}
}/*if(do_symtab)*/
/* Print the common blocks */
if(do_symtab || port_check || f77_standard) {
int i,numblocks;
for(i=0,numblocks=0;i<loc_symtab_top;i++) {
if(storage_class_of(loc_symtab[i].type) == class_COMMON_BLOCK) {
sym_list[numblocks++] = &loc_symtab[i];
}
}
if(numblocks != 0) {
sort_symbols(sym_list,numblocks);
if(do_symtab) {
(void)fprintf(list_fd,"\nCommon blocks referenced:\n");
(void) print_symbols(list_fd,sym_list,numblocks,FALSE);
}
if(port_check || f77_standard) {
check_mixed_common(list_fd,sym_list,numblocks);
}
}
}/*if(do_symtab||port_check)*/
/* Print the namelists */
if(do_symtab) {
int i,numlists;
for(i=0,numlists=0;i<loc_symtab_top;i++) {
if(storage_class_of(loc_symtab[i].type) == class_NAMELIST) {
sym_list[numlists++] = &loc_symtab[i];
}
}
if(numlists != 0) {
sort_symbols(sym_list,numlists);
if(do_symtab) {
(void)fprintf(list_fd,"\nNamelists defined:\n");
(void) print_symbols(list_fd,sym_list,numlists,FALSE);
}
}
}/* End printing the namelists */
/* Process the variables */
if(do_symtab || usage_check) {
int i,n;
for(i=0,n=0;i<loc_symtab_top;i++) {
if(storage_class_of(loc_symtab[i].type) == class_VAR
&& (!loc_symtab[i].entry_point || this_is_a_function)) {
sym_list[n++] = &loc_symtab[i];
if(loc_symtab[i].argument && loc_symtab[i].set_flag) {
if(++args_modified <= 3)
if(this_is_a_function && pure_functions) {
identify_module(mod_name);
(void)fprintf(list_fd,
"Function %s %s argument %s",
mod_name,
loc_symtab[i].assigned_flag?
"modifies":"may modify",
loc_symtab[i].name);
}
}
if(loc_symtab[i].common_var && loc_symtab[i].set_flag) {
if(++com_vars_modified <= 3)
if(this_is_a_function && pure_functions) {
identify_module(mod_name);
(void)fprintf(list_fd,
"Function %s %s common variable %s",
mod_name,
loc_symtab[i].assigned_flag?
"modifies":"may modify",
loc_symtab[i].name);
}
}
}
}
if(args_modified > 3 || com_vars_modified > 3)
if(this_is_a_function && pure_functions)
(void)fprintf(list_fd,"\netc...");
if(n != 0) {
sort_symbols(sym_list,n);
/* Print the variables */
if(do_symtab) {
(void)fprintf(list_fd,"\nVariables:\n ");
imps += print_variables(sym_list,n);
}
}
/* Explain the asterisk on implicitly defined
identifiers. Note that this message will
be given also if functions implicitly defined */
if(do_symtab && imps != 0) {
(void)fprintf(list_fd,"\n* Variable not declared.");
(void)fprintf(list_fd," Type has been implicitly defined.\n");
++warning_count;
}
if(usage_check) {
if(do_symtab || do_list)
(void)fprintf(list_fd,"\n");
if(check_unused) {
check_flags(sym_list,n,0,0,0,
"declared but never referenced",mod_name);
check_flags(sym_list,n,0,1,0,
"set but never used",mod_name);
}
if(check_set_used) {
check_flags(sym_list,n,1,0,1,
"used before set",mod_name);
check_flags(sym_list,n,1,1,1,
"may be used before set",mod_name);
}
}/*end if(usage_check)*/
if(do_symtab || do_list)
(void)fprintf(list_fd,"\n");
}/* end if(do_symtab || usage_check) */
/* List all undeclared vars & functions */
if(decls_required || implicit_none) {
int i,n;
for(i=0,n=0;i<loc_symtab_top;i++) {
if(datatype_of(loc_symtab[i].type) == type_UNDECL
&& ! loc_symtab[i].intrinsic /* omit intrinsics */
/* omit subroutines called */
&& (!loc_symtab[i].external || loc_symtab[i].invoked_as_func)
) {
sym_list[n++] = &loc_symtab[i];
}
}
if(n != 0) {
sort_symbols(sym_list,n);
identify_module(mod_name);
(void)fprintf(list_fd,
"Identifiers of undeclared type");
(void) print_symbols(list_fd,sym_list,n,FALSE);
}
}/*if(decls_required || implicit_none)*/
/* Under -f77, list any nonstandard intrinsics used */
if(f77_standard) {
int i,n;
for(i=0,n=0;i<loc_symtab_top;i++) {
if(storage_class_of(loc_symtab[i].type) == class_SUBPROGRAM
&& loc_symtab[i].intrinsic &&
(loc_symtab[i].info.intrins_info->intrins_flags & I_NONF77)) {
sym_list[n++] = &loc_symtab[i];
}
}
if(n != 0) {
sort_symbols(sym_list,n);
identify_module(mod_name);
(void)fprintf(list_fd,"Nonstandard intrinsic functions referenced:\n");
(void) print_symbols(list_fd,sym_list,n,FALSE);
}
}/*if(f77_standard)*/
/* issue -f77 warning for identifiers
longer than 6 characters
*/
if(f77_standard) {
int i,n;
for(i=0,n=0;i<loc_symtab_top;i++) {
if(strlen(loc_symtab[i].name) > (unsigned)6)
sym_list[n++] = &loc_symtab[i];
}
if(n != 0) {
sort_symbols(sym_list,n);
++warning_count;
identify_module(mod_name);
(void)fprintf(list_fd,
"Names longer than 6 chars (nonstandard):");
(void) print_symbols(list_fd,sym_list,n,FALSE);
}
}
/* If -f77 flag given, list names with underscore or dollarsign */
if(f77_standard || !allow_underscores || !allow_dollarsigns) {
int i,n;
for(i=0,n=0;i<loc_symtab_top;i++) {
/* Find all names with nonstd chars, but
exclude internal names like %MAIN */
if(has_nonalnum(loc_symtab[i].name) &&
loc_symtab[i].name[0] != '%')
sym_list[n++] = &loc_symtab[i];
}
if(n != 0) {
sort_symbols(sym_list,n);
++warning_count;
identify_module(mod_name);
(void)fprintf(list_fd,
"Names containing nonstandard characters");
(void) print_symbols(list_fd,sym_list,n,FALSE);
}
}/*if(f77_standard || !allow_underscores || !allow_dollarsigns)*/
/* Print out clashes in first six chars of name */
if(sixclash) {
int n;
n = find_sixclashes(sym_list);
if(n != 0) {
sort_symbols(sym_list,n);
identify_module(mod_name);
(void)fprintf(list_fd,
"Identifiers which are not unique in first six chars");
(void) print_symbols(list_fd,sym_list,n,FALSE);
}/* end if(n != 0) */
}/* end if(sixclash) */
/* If portability flag was given, check equivalence
groups for mixed type. */
if(port_check || local_wordsize==0) {
int i,j,n;
int imps=0;
Lsymtab *equiv;
/* scan thru table for equivalenced variables */
for(i=0;i<loc_symtab_top;i++) {
if(storage_class_of(loc_symtab[i].type) == class_VAR
&& loc_symtab[i].equiv_link != (equiv= &loc_symtab[i]) ){
n=0;
do {
if(equiv < &loc_symtab[i]) { /* skip groups done before */
n=0;
break;
}
sym_list[n++] = equiv;
equiv = equiv->equiv_link;
} while(equiv != &loc_symtab[i]); /* complete the circle */
/* Check for mixed types */
if(n != 0) {
int mixed_type = FALSE, mixed_size = FALSE,
mixed_default_size = FALSE;
int t1,t2,s1,s2,defsize1,defsize2;
t1 = get_type(sym_list[0]);
s1 = get_size(sym_list[0],t1);
defsize1 = (s1 == size_DEFAULT);
if(s1 == size_DEFAULT) s1 = type_size[t1];
for(j=1; j<n; j++) {
t2 = get_type(sym_list[j]);
s2 = get_size(sym_list[j],t2);
defsize2 = (s2 == size_DEFAULT);
if(s2 == size_DEFAULT) s2 = type_size[t2];
if( t1 == t2 ) {
if( t1 != type_STRING ){
/* Same non-char types: size must match */
if( s1 != s2 ) {
mixed_size = TRUE;
break;
}
else if(defsize1 != defsize2) {
mixed_default_size = TRUE;
break;
}
}
}
else {/* Different types */
/* It is nonportable to equivalence:
Real*8 to Double or
Complex*16 to DComplex */
if(type_category[t1] == type_category[t2]) {
if( s1 != s2 ) {
mixed_size = TRUE;
break;
}
else if(defsize1 != defsize2) {
mixed_default_size = TRUE;
break;
}
}
/* It is standard and portable to equivalence:
Real to Complex or
Double to DComplex */
else if(equiv_type[t1] == equiv_type[t2]) {
if( ((type_category[t1] == type_COMPLEX)?
s1 != 2*s2: s2 != 2*s1) ) {
mixed_size = TRUE;
break;
}
else if(defsize1 != defsize2) {
mixed_default_size = TRUE;
break;
}
}
else {
mixed_type = TRUE;
break;
}
}/*end else different types*/
t1 = t2;
s1 = s2;
defsize1 = defsize2;
}/*end for j*/
if(mixed_type || mixed_size || mixed_default_size) {
sort_symbols(sym_list,n);
identify_module(mod_name);
(void)fprintf(list_fd,
"Mixed %s equivalenced (not portable):",
mixed_type?"types":
mixed_size?"sizes":
"default and explicit size items");
imps += print_symbols(list_fd,sym_list,n,TRUE);
}
}
}
}
if(imps != 0) {
identify_module(mod_name);
(void)fprintf(list_fd,"* Variable not declared.");
(void)fprintf(list_fd," Type has been implicitly defined.\n");
}
}/*if(port_check)*/
make_declarations(sym_list,mod_name);
}/* print_loc_symbols */
PRIVATE int
has_nonalnum(s) /* Returns TRUE if s contains a non-alphanumeric character
and -f77, or if it has $ or _ and that is not allowed */
char *s;
{
while( *s != '\0' ) {
if( (f77_standard && ! isalnum( (int)(*s) ))
|| (!allow_dollarsigns && (*s) == '$')
|| (!allow_underscores && (*s) == '_') )
return TRUE;
s++;
}
return FALSE;
}
/* This routine prints symbol names neatly. If do_types is true
also prints types, with * next to implicitly
typed identifiers, and returns count thereof. */
PRIVATE int
print_symbols(fd,sym_list,n,do_types)
FILE *fd;
Lsymtab *sym_list[];
int n;
int do_types;
{
int i,col=0,len,implicits=0;
(void)fprintf(fd,"\n");
for(i=0;i<n;i++) {
len = strlen(sym_list[i]->name);/* len=actual length of name */
/* Revise len to max(10,len)+extra 9=width
of field to be printed. Adjust column
count to see where this will take us. */
col += len = (len <= 10? 10: len) + 9;
/* If this will run past 78 start a new line */
if(col > 78) {
(void)fprintf(fd,"\n");
col = len;
}
(void)fprintf(fd,"%10s",sym_list[i]->name);/* Print the name in 10 cols */
if( do_types ) { /* Optionally print the datatype */
if(sym_list[i]->intrinsic)
(void)fprintf(fd,": intrns ");
else {
(void)fprintf(fd,":");
(void) print_var_type(fd,sym_list[i]);
if(datatype_of(sym_list[i]->type) == type_UNDECL) {
implicits++; /* Flag and count undeclareds */
(void)fprintf(fd,"*");
}
else if(sym_list[i]->size == size_DEFAULT)
(void)fprintf(fd," ");
(void)fprintf(fd," ");
}
}
else /* Otherwise just 9 blanks */
(void)fprintf(fd,"%9s","");
}
(void)fprintf(fd,"\n");
return implicits;
}/*print_symbols*/
/* This routine prints the variables nicely, and returns
count of number implicitly defined.
*/
PRIVATE int
print_variables(sym_list,n)
Lsymtab *sym_list[];
int n;
{
int i,implicits=0,adjustables=0;
(void)fprintf(list_fd,"\n ");
for(i=0; i<4; i++) {
(void)fprintf(list_fd,"%5sName Type Dims","");
/* 12345678901234567890 template for above*/
}
for(i=0; i<n; i++) {
if(i % 4 == 0)
(void)fprintf(list_fd,"\n");
else
(void)fprintf(list_fd," ");
(void)fprintf(list_fd,"%10s",sym_list[i]->name);
adjustables += print_var_type(list_fd,sym_list[i]);
/* Print a * next to implicitly declared variables */
if(datatype_of(sym_list[i]->type) == type_UNDECL ) {
implicits++;
(void)fprintf(list_fd,"*");
}
else if(sym_list[i]->size == size_DEFAULT)
(void)fprintf(list_fd," "); /* print blank if no size or * */
/* print no. of dimensions next to var name */
if(sym_list[i]->array_var) {
(void)fprintf(list_fd," %ld",
array_dims(sym_list[i]->info.array_dim));
}
else {
(void)fprintf(list_fd,"%2s","");
}
}
if(adjustables > 0)
(void)fprintf(list_fd,"\nchar+ indicates adjustable size");
(void)fprintf(list_fd,"\n");
return implicits;
}/*print_variables*/
PRIVATE int
print_var_type(fd,symt) /* Prints type name then size if explicit */
/* Returns 1 if adjustable size, else 0 */
FILE *fd;
Lsymtab *symt;
{
int adjustable=0;
int t = get_type(symt);
int s = get_size(symt,t);
(void)fprintf(fd," %4s",type_name[t]);
/* Usually either size or * will be printed, and usually
size is 1 digit. So mostly we print 1 column in
the next set of (void)fprintf's. Output will be ragged
if size > 9 or implicit type has explicit size. */
if( s != size_DEFAULT ) {
if(t != type_STRING || s > 1)
(void)fprintf(fd,"%d",s);
else
if(s == size_ADJUSTABLE) {
adjustable++;
(void)fprintf(fd,"+");
}
else
(void)fprintf(fd," ");
}
return adjustable;
}
/* Search thru local symbol table for clashes where identifiers
are not unique in 1st six characters. Return value =
number of clashes found, with pointers to symbol table
entries of clashers in array list. */
PRIVATE int
find_sixclashes(list)
Lsymtab *list[];
{
int i,h, clashes=0;
int class;
unsigned long hnum;
for(i=0; i<loc_symtab_top; i++) { /* Scan thru symbol table */
class = storage_class_of(loc_symtab[i].type);
hnum = hash( loc_symtab[i].name );
/* First look for a clash of any kind.
(N.B. this loop will never quit if hash
table is full, but let's not worry) */
while( (h=hnum % HASHSZ), hashtab[h].name != (char *)NULL) {
/* Now see if the clashing name is used locally and still
clashes at 6 chars. Treat common blocks separately. */
if((class == class_COMMON_BLOCK &&
(
hashtab[h].com_loc_symtab != NULL
&& strcmp( hashtab[h].name,loc_symtab[i].name) != 0
&& strncmp(hashtab[h].name,loc_symtab[i].name,6) == 0
)
) ||
(class != class_COMMON_BLOCK &&
(
hashtab[h].loc_symtab != NULL
&& strcmp( hashtab[h].name,loc_symtab[i].name) != 0
&& strncmp(hashtab[h].name,loc_symtab[i].name,6) == 0
)
)
) {
/* If so, then i'th symbol is a clash */
list[clashes++] = &loc_symtab[i];
break;
}
else {
hnum = rehash(hnum);
}
}
}
return clashes;
}
#ifdef DEBUG_SYMTABS
PRIVATE void
print_arg_array(arglist) /* prints type and flag info for arguments */
ArgListHeader *arglist;
{
int i, count;
ArgListElement *a;
count = arglist->numargs;
if(arglist->external_decl || arglist->actual_arg)
count = 0;
a = arglist->arg_array;
(void)fprintf(list_fd,"\nArg list in module %s file %s line %u:",
arglist->module->name, arglist->filename, arglist->line_num);
(void)fprintf(list_fd,"\n\tdef%d call%d ext%d arg%d",
arglist->is_defn,
arglist->is_call,
arglist->external_decl,
arglist->actual_arg);
if(count == 0)
(void)fprintf(list_fd,"\n(Empty list)");
else {
for (i=0; i<count; i++) {
(void)fprintf(list_fd,
"\n\t%d %s: lv%d st%d as%d ub%d ar%d ae%d ex%d",
i+1,
type_name[datatype_of(a[i].type)],
a[i].is_lvalue,
a[i].set_flag,
a[i].assigned_flag,
a[i].used_before_set,
a[i].array_var,
a[i].array_element,
a[i].declared_external);
if(a[i].array_var)
(void)fprintf(list_fd,"(%ld,%ld)",
array_dims(a[i].info.array_dim),
array_size(a[i].info.array_dim) );
(void)fprintf(list_fd,", ");
}
}
}/* print_arg_array */
#endif
#ifdef DEBUG_SYMTABS
/* prints type and dimen info for common vars */
PRIVATE void
print_com_array(cmlist)
ComListHeader *cmlist;
{
int i, count;
ComListElement *c;
count = cmlist->numargs;
c = cmlist->com_list_array;
(void)fprintf(list_fd,"\nCom list in module %s file %s line %u:",
cmlist->module->name, cmlist->filename, cmlist->line_num);
(void)fprintf(list_fd,"\n\t");
if(count == 0)
(void)fprintf(list_fd,"(Empty list)");
else {
for (i=0; i<count; i++){
(void)fprintf(list_fd,"%s",type_name[datatype_of(c[i].type)]);
if(c[i].dimen_info)
(void)fprintf(list_fd,":%ldD(%ld)",array_dims(c[i].dimen_info),
array_size(c[i].dimen_info));
(void)fprintf(list_fd,", ");
}
}
}/* print_com_array */
#endif
#if 0 /* debugging code not currently in use */
PRIVATE void
print_tokenlist(toklist) /* prints list of token names or types */
TokenListHeader *toklist;
{
int numargs=0;
Token *t;
(void)fprintf(list_fd,"\n");
if (toklist == NULL){
(void)fprintf(list_fd,"\t(No list)");
}
else {
t = toklist->tokenlist;
while(t != NULL){
++numargs;
(void)fprintf(list_fd," ");
if ( is_true(ID_EXPR,t->TOK_flags) )
(void)fprintf(list_fd,"%s ",token_name(*t));
else
(void)fprintf(list_fd,"%s ",
type_name[datatype_of(t->TOK_type)]);
t = t->next_token;
}
if(numargs == 0)
(void)fprintf(list_fd,"\t(Empty list)");
}
}/* print_tokenlist */
#endif
PRIVATE int
make_sym_list(sym_list,select)
Lsymtab *sym_list[];
int (*select)();
{
int i;
int n;
for (i = 0, n = 0; i < loc_symtab_top; ++i)
{
if (select(&loc_symtab[i]))
sym_list[n++] = &loc_symtab[i];
}
if (n > 0)
{
/* original PARAMETER statement order must be preserved so that
the expressions do not refer to as-yet-undefined parameter names */
if (select == select_parameters)
sort_positions(sym_list,n);
else
sort_symbols(sym_list,n);
}
return (n);
}
PRIVATE void
check_mixed_common(fd,sym_list,n)
FILE *fd;
Lsymtab *sym_list[];
int n;
{
int i;
for(i=0; i<n; i++) {
ComListHeader *chead = sym_list[i]->info.comlist;
ComListElement *clist;
char *mod_name;
int j,nvars;
int has_char=FALSE,has_nonchar=FALSE;
int prev_size = 0;
/* initialize to remove lint warning about use before definition */
int this_size, this_type;
if(chead == NULL)
continue;
mod_name = chead->module->name;
clist=chead->com_list_array;
nvars = chead->numargs;
for(j=0; j<nvars; j++) {
/* Check conformity to ANSI rule: no mixing char with other types */
if( (this_type=datatype_of(clist[j].type)) == type_STRING) {
has_char = TRUE;
this_size = 1;/* char type size is 1 for alignment purposes */
}
else { /* other types use declared sizes */
has_nonchar = TRUE;
if( (this_size=clist[j].size) == size_DEFAULT)
this_size = type_size[this_type];
}
if(has_char && has_nonchar) {
if(f77_standard){
identify_module(mod_name);
(void)fprintf(fd,
"Common block %s line %u has mixed",
sym_list[i]->name,
chead->line_num);
(void)fprintf(fd,
"\n character and non-character variables (nonstandard)");
}
break;
}
/* Check that variables are in descending order of type size */
if(j > 0) {
if( this_size > prev_size ) {
if(port_check) {
identify_module(mod_name);
(void)fprintf(fd,
"Common block %s line %u has long data type",
sym_list[i]->name,
chead->line_num);
(void)fprintf(fd,
"\n following short data type (may not be portable)");
}
break;
}
}
prev_size = this_size;
}
}
}
PRIVATE void
check_flags(list,n,used,set,ubs,msg,mod_name)
Lsymtab *list[];
int n;
unsigned used,set,ubs;
char *msg,*mod_name;
{
int matches=0,col=0,unused_args=0,i,len;
unsigned pattern = flag_combo(used,set,ubs);
for(i=0;i<n;i++) {
if( list[i]->common_var ) /* common vars are immune */
continue;
/* for args, do only 'never used' */
if( list[i]->argument && pattern != flag_combo(0,0,0) )
continue;
#ifdef ALLOW_INCLUDE
/* Skip variables 'declared but not used'
and parameters 'set but never used'
if defined in include file. */
if( list[i]->defined_in_include &&
( pattern == flag_combo(0,0,0)
|| (list[i]->parameter && pattern == flag_combo(0,1,0)) ) )
continue;
#endif
/* function return val: ignore 'set but never used' */
if( list[i]->entry_point && pattern == flag_combo(0,1,0) )
continue;
if(flag_combo(list[i]->used_flag,list[i]->set_flag,
list[i]->used_before_set) == pattern) {
if(matches++ == 0) {
identify_module(mod_name);
(void)fprintf(list_fd,
"Variables %s:\n",
msg);
}
len = strlen(list[i]->name);
col += len = (len <= 10? 10: len) + 9;
if(col > 78) {
(void)fprintf(list_fd,"\n");
col = len;
}
(void)fprintf(list_fd,"%10s",list[i]->name);
/* arg never used: tag with asterisk */
(void)fprintf(list_fd,"%-9s",
list[i]->argument? (++unused_args,"*") : "" );
}
}
if(unused_args > 0)
(void)fprintf(list_fd,"\n * Dummy argument");
if(matches > 0)
(void)fprintf(list_fd,"\n");
}
void
debug_symtabs() /* Debugging output: hashtable and symbol tables */
{
#ifdef DEBUG_SYMTABS
if(debug_loc_symtab) {
(void)fprintf(list_fd,"\n Debugging of local symbol table disabled");
return;
}
if(debug_hashtab) {
int i;
(void)fprintf(list_fd,"\n\nContents of hashtable\n");
for(i=0; i<HASHSZ; i++) {
if(hashtab[i].name != NULL) {
(void)fprintf(list_fd,"\n%4d %s",i,hashtab[i].name);
if(hashtab[i].loc_symtab != NULL)
(void)fprintf(list_fd," loc %d",hashtab[i].loc_symtab-loc_symtab);
if(hashtab[i].glob_symtab != NULL)
(void)fprintf(list_fd,
" glob %d",hashtab[i].glob_symtab-glob_symtab);
if(hashtab[i].com_loc_symtab != NULL)
(void)fprintf(list_fd,
" Cloc %d",hashtab[i].com_loc_symtab-loc_symtab);
if(hashtab[i].com_glob_symtab != NULL)
(void)fprintf(list_fd,
" Cglob %d",hashtab[i].com_glob_symtab-glob_symtab);
}
}
}
if(debug_glob_symtab) {
int i;
(void)fprintf(list_fd,"\n\nContents of global symbol table");
for(i=0; i<glob_symtab_top; i++) {
(void)fprintf(list_fd,
"\n%4d %s type 0x%x=%s,%s: ",
i,
glob_symtab[i].name,
glob_symtab[i].type,
class_name[storage_class_of(glob_symtab[i].type)],
type_name[datatype_of(glob_symtab[i].type)]
);
(void)fprintf(list_fd,
"usd%d set%d asg%d ubs%d lib%d int%d invf%d vis%d smw%d incl%d ext%d ",
glob_symtab[i].used_flag,
glob_symtab[i].set_flag,
glob_symtab[i].assigned_flag,
glob_symtab[i].used_before_set,
glob_symtab[i].library_module,
glob_symtab[i].internal_entry,
glob_symtab[i].invoked_as_func,
glob_symtab[i].visited,
glob_symtab[i].visited_somewhere,
glob_symtab[i].defined_in_include,
glob_symtab[i].declared_external
);
switch(storage_class_of(glob_symtab[i].type)){
case class_COMMON_BLOCK:{
ComListHeader *clist;
clist=glob_symtab[i].info.comlist;
while(clist != NULL){
print_com_array(clist);
clist = clist->next;
}
break;
}
case class_SUBPROGRAM:{
ArgListHeader *alist;
alist=glob_symtab[i].info.arglist;
while(alist != NULL){
print_arg_array(alist);
alist = alist->next;
}
break;
}
}
}
}
#endif
}/* debug_symtabs*/
/*----------------Additions for declaration file output----------------*/
/* Originally written by Nelson H.F. Beebe before source text was
saved in the symbol table. Rewritten by R. Moniot to make use
of said text. */
/* Only make_declarations() is used by the above routines */
PRIVATE char
*get_dimension_list();
PRIVATE char
*get_parameter_value();
PRIVATE char
*get_size_expression();
#if 0 /* This is how Beebe wrote it */
#define ACTUAL_SIZE(p) (((p)->size == 0) ? \
std_size[the_type] : (p)->size)
#else
/* This is what it has to be if IMPLICIT types supported */
#define ACTUAL_SIZE(p) (get_size((p),sym_type))
#endif
#define DCL_FLAGS_DECLARATIONS 0x0001
#define DCL_FLAGS_ONLY_UNDECLARED 0x0002
#define DCL_FLAGS_COMPACT 0x0004
#define DCL_FLAGS_USE_CONTINUATIONS 0x0008
#define DCL_FLAGS_KEYWORDS_LOWERCASE 0x0010
#define DCL_FLAGS_VARIABLES_AND_CONSTANTS_LOWERCASE 0x0020
#define DCL_FLAGS_EXCLUDE_SFTRAN3_INTERNAL_VARIABLES 0x0040
#define DCL_FLAGS_ASTERISK_COMMENT_CHARACTER 0x0080
#define DCL_FLAGS_LOWERCASE_COMMENT_CHARACTER 0x0100
#define COLUMN_WIDTH 13
#define DECLARE_ONLY_UNDECLARED() (make_dcls & DCL_FLAGS_ONLY_UNDECLARED)
#define DECLARE_COMPACT() (make_dcls & DCL_FLAGS_COMPACT)
#define NO_CONTINUATION_LINES() (!(make_dcls & DCL_FLAGS_USE_CONTINUATIONS))
#define SF3_DECLARATIONS() \
(make_dcls & DCL_FLAGS_EXCLUDE_SFTRAN3_INTERNAL_VARIABLES)
#define ASTERISK_COMMENT_CHAR() \
(make_dcls & DCL_FLAGS_ASTERISK_COMMENT_CHARACTER)
#define KEYWORDS_LOWERCASE() (make_dcls & DCL_FLAGS_KEYWORDS_LOWERCASE)
#define LOWERCASE_COMMENT_CHARACTER() \
(make_dcls & DCL_FLAGS_LOWERCASE_COMMENT_CHARACTER)
#define VARIABLES_AND_CONSTANTS_LOWERCASE() \
(make_dcls & DCL_FLAGS_VARIABLES_AND_CONSTANTS_LOWERCASE)
#ifndef FIRST_VARIABLE_COLUMN
#define FIRST_VARIABLE_COLUMN 26 /* to match Extended PFORT Verifier */
#endif
#define NEXT_COLUMN(column) (FIRST_VARIABLE_COLUMN + \
(((column) - FIRST_VARIABLE_COLUMN + \
COLUMN_WIDTH - 1) / COLUMN_WIDTH)*COLUMN_WIDTH)
#define isaletter(C) isalpha((int)(C))
/* define isidletter to allow underscore and/or dollar sign */
#define isidletter(C) (isalpha((int)(C)) || (C) == '_' || (C) == '$')
#define makelower(C) (isupper((int)(C)) ? tolower((int)(C)) : (int)(C))
#define makeupper(C) (islower((int)(C)) ? toupper((int)(C)) : (int)(C))
PRIVATE char *begin_module;
#define MAX_STMT (72 + 19*72 + 1) /* longest Fortran stmt */
PRIVATE char stmt_fragment[MAX_STMT];
PRIVATE char comment_char = 'C'; /* default value */
PRIVATE int std_size[] = /* NB: depends on type_XXX order in symtab.h */
{
0, /* unknown */
4, /* INTEGER*4 */
4, /* REAL*4 */
8, /* DOUBLE PRECISION == REAL*8 */
8, /* COMPLEX*8 */
16, /* DOUBLE COMPLEX == COMPLEX*16 */
4, /* LOGICAL*4 */
1 /* CHARACTER*1 == CHARACTER */
};
PRIVATE int
pos_fragment = 0; /* cursor in stmt_fragment buffer */
PRIVATE void
append_char_to_fragment(c)
int c;
{
if (pos_fragment < (MAX_STMT - 1))
stmt_fragment[pos_fragment++] = c;
}
PRIVATE void
append_string_to_fragment(s)
char *s;
{
while (*s)
append_char_to_fragment(*s++);
}
/* Appends source text of an expression, up- or
down-casing the letters according to pref. */
PRIVATE void
append_expr_text_to_fragment(s)
char *s;
{
int quote_char, inside_quote;
inside_quote = FALSE;
for (; *s; ++s) {
if(! inside_quote) {
if(*s == '\'' || *s == '"') { /* Start of a quote */
inside_quote = TRUE;
quote_char = *s;
}
append_char_to_fragment(VARIABLES_AND_CONSTANTS_LOWERCASE()
? makelower(*s) : makeupper(*s));
}
else { /* inside quote */
if(*s == quote_char) { /* End of quote (quoted quote_char is handled
as if consecutive strings) */
inside_quote=FALSE;
}
append_char_to_fragment(*s);
}
}
}
PRIVATE char *
get_dimension_list(symt)
Lsymtab *symt;
{
int n, dims;
/* Get list of array dimensions from symbol table */
new_fragment();
append_char_to_fragment('(');
dims = array_dims(symt->info.array_dim);
for (n = 0; n < dims; ++n)
{
if (n > 0)
append_char_to_fragment(',');
append_expr_text_to_fragment(symt->src.textvec[n]);
}
append_char_to_fragment(')');
append_char_to_fragment('\0');
return (&stmt_fragment[0]);
}
PRIVATE char *
get_parameter_value(symt)
Lsymtab *symt;
{
/* Construct parameter list "(NAME = value)" */
new_fragment();
append_char_to_fragment('(');
append_expr_text_to_fragment(symt->name);
append_string_to_fragment(" = ");
append_expr_text_to_fragment(symt->info.param->src_text);
append_char_to_fragment(')');
append_char_to_fragment('\0');
return (&stmt_fragment[0]);
}
PRIVATE char *
get_size_expression(symt)
Lsymtab *symt;
{
/* Get a CHARACTER size expression from the symbol table */
new_fragment();
append_char_to_fragment('*');
append_expr_text_to_fragment(get_size_text(symt,0));
append_char_to_fragment('\0');
return (&stmt_fragment[0]);
}
PRIVATE void
make_declarations(sym_list,mod_name)
Lsymtab *sym_list[];
char *mod_name;
{
char *header;
char begin[72+1+2+1];
int len_current_filename = strlen(current_filename);
if (!make_dcls)
return;
make_dcls |= DCL_FLAGS_DECLARATIONS; /* any non-zero value selects */
if (LOWERCASE_COMMENT_CHARACTER())
comment_char = 'c';
else if (ASTERISK_COMMENT_CHAR())
comment_char = '*';
else
comment_char = 'C';
/* In the event there are no declarations to be output, we want
the declaration file to be empty, because that reduces the
number of files that the user has to deal with. In fact, if it
IS empty, it will be deleted on close. Instead of printing the
module header comment here, we point a global pointer at it,
and then in the print_xxx() functions, print the header before
the first declaration that is output.
We also need to take care not be overwrite the begin[] array,
which could happen if the module name or file name are
exceptionally long. We therefore take at most 8 characters
from the start of the module name, and at most 12 (because 12 =
8 + 1 + 3 for IBM PC DOS), from the END of the filename,
discarding a long directory path prefix if necessary. */
(void)sprintf(begin,
"%c====>Begin Module %-8s File %-12s %s\n%c\n",
comment_char,
mod_name,
(len_current_filename > 12) ?
(current_filename + len_current_filename - 12) :
current_filename,
DECLARE_ONLY_UNDECLARED() ?
"Undeclared variables" : "All variables",
comment_char);
begin_module = &begin[0];
print_selected_declarations(sym_list,
make_sym_list(sym_list,
select_intrinsics_by_name),
type_ERROR, "INTRINSIC",
(header = "Intrinsic functions", &header));
print_declaration_class(sym_list,
make_sym_list(sym_list,select_intrinsics_by_type),
(header = "Built-in functions", &header));
print_selected_declarations(sym_list,
make_sym_list(sym_list,
select_externals_by_name),
type_ERROR, "EXTERNAL",
(header = "External functions", &header));
print_declaration_class(sym_list,
make_sym_list(sym_list,select_externals_by_type),
(char*)NULL);
print_declaration_class(sym_list,
make_sym_list(sym_list,select_statement_functions),
"Statement functions");
print_declaration_class(sym_list,
make_sym_list(sym_list,select_parameters),
"Parameter variables");
print_declaration_class(sym_list,
make_sym_list(sym_list,select_arguments),
"Argument variables");
print_declaration_class(sym_list,
make_sym_list(sym_list,select_locals),
"Local variables");
print_list_decls(sym_list,
make_sym_list(sym_list,select_common_blocks),
"Common blocks","COMMON");
print_list_decls(sym_list,
make_sym_list(sym_list,select_namelists),
"Namelists","NAMELIST");
if (begin_module == (char*)NULL) /* then need a trailer comment */
(void)fprintf(dcl_fd,
"%c====>End Module %-8s File %-12s\n",
comment_char,
mod_name,
(len_current_filename > 12) ?
(current_filename + len_current_filename - 12) :
current_filename);
}
PRIVATE void
maybe_print_module_header()
{
if (begin_module != (char*)NULL)
{ /* print module header comment only once */
(void)fputs(begin_module, dcl_fd);
begin_module = (char*)NULL;
}
}
PRIVATE void
new_fragment()
{
pos_fragment = 0;
}
PRIVATE void
print_blanks(nblanks)
int nblanks;
{
for ( ; nblanks > 0; --nblanks)
(void)putc(' ',dcl_fd);
}
/* Routine to print namelist and
common declarations. */
PRIVATE void
print_common_decls(sym_entry)
Lsymtab *sym_entry; /* COMMON block symbol table entry */
{
int h;
int n;
Token *t;
#ifdef DYNAMIC_TABLES /* tables will be mallocked at runtime */
static Lsymtab **sym_list=(Lsymtab **)NULL;
if(sym_list == (Lsymtab **)NULL) { /* Initialize if not done before */
if( (sym_list=(Lsymtab **)calloc(LOCSYMTABSZ,sizeof(Lsymtab *)))
== (Lsymtab **)NULL) {
oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM,
"Cannot malloc space for local symbol list");
}
}
#else
Lsymtab *sym_list[LOCSYMTABSZ]; /* temp. list of symtab entries to print */
#endif
for (n = 0, t = sym_entry->src.toklist->tokenlist;
t != NULL;
t = t->next_token)
{
h = t->value.integer;
sym_list[n++] = hashtab[h].loc_symtab;
}
if (n > 0)
{
sort_symbols(sym_list,n);
print_declaration_class(sym_list, n, "Common variables");
}
}
PRIVATE void
print_empty_comment_line()
{
(void)putc(comment_char,dcl_fd);
(void)putc('\n',dcl_fd);
}
PRIVATE void
print_equivalence_decls(sym_entry)
Lsymtab *sym_entry; /* COMMON block symbol table entry */
{
int h;
int n;
Lsymtab *s;
Token *t;
#ifdef DYNAMIC_TABLES /* tables will be mallocked at runtime */
static Lsymtab **sym_list=(Lsymtab **)NULL;
if(sym_list == (Lsymtab **)NULL) { /* Initialize if not done before */
if( (sym_list=(Lsymtab **)calloc(LOCSYMTABSZ,sizeof(Lsymtab *)))
== (Lsymtab **)NULL) {
oops_message(OOPS_FATAL,NO_LINE_NUM,NO_COL_NUM,
"Cannot malloc space for local symbol list");
}
}
#else
Lsymtab *sym_list[LOCSYMTABSZ]; /* temp. list of symtab entries to print */
#endif
for (n = 0, t = sym_entry->src.toklist->tokenlist;
t != NULL;
t = t->next_token)
{
h = t->value.integer;
for (s = hashtab[h].loc_symtab, s = s->equiv_link;
(s != NULL) && (s != hashtab[h].loc_symtab);
s = s->equiv_link)
sym_list[n++] = s;
}
if (n > 0)
{
sort_symbols(sym_list,n);
print_declaration_class(sym_list, n,
"Equivalenced common variables");
}
}
PRIVATE int
count_undeclared_variables(sym_entry)
Lsymtab *sym_entry;
{
int count, h;
Token *t;
Lsymtab *symt;
for (count = 0, t = sym_entry->src.toklist->tokenlist;
t != NULL;
t = t->next_token)
{ /* Loop over members */
h = t->value.integer;
symt = hashtab[h].loc_symtab;
if (datatype_of(symt->type) == type_UNDECL)
count++;
}
return (count);
}
PRIVATE void
print_list_decls(sym_list, n, header, list_type_name)
Lsymtab *sym_list[];
int n;
char *header;
char *list_type_name;
{
int i, nd;
if (DECLARE_ONLY_UNDECLARED() &&
(strcmp(list_type_name,"NAMELIST") == 0)) /* These lists are always declared */
return;
nd = 0;
for (i=0; i<n; i++)
{ /* Loop over COMMON or NAMELIST lists */
if (sym_list[i]->src.toklist != NULL)
{
if (strcmp(list_type_name,"COMMON") == 0)
{ /* then COMMON list */
if (!DECLARE_ONLY_UNDECLARED() ||
(DECLARE_ONLY_UNDECLARED() &&
(count_undeclared_variables(sym_list[i]) > 0)))
{
print_common_decls(sym_list[i]);
if (!DECLARE_ONLY_UNDECLARED())
print_one_list_decls(sym_list[i], list_type_name,
&header, &nd);
print_equivalence_decls(sym_list[i]);
}
}
else /* must be NAMELIST list */
print_one_list_decls(sym_list[i], list_type_name, &header, &nd);
}
}
if ((nd > 0) && (strcmp(list_type_name,"COMMON") != 0))
print_empty_comment_line();
}
/* routine to print COMMON or NAMELIST
name between slashes. */
PRIVATE int
print_list_name(list_type_name,name)
char *list_type_name;
char *name;
{
int column, len;
char *p;
maybe_print_module_header();
/* Compact mode: COMMON /blknam/
Padded mode: COMMON / blknam /
*/
print_blanks(6);
column = 6;
for (p = list_type_name; *p; ++p, ++column)
(void)putc(KEYWORDS_LOWERCASE() ? makelower(*p) : makeupper(*p),
dcl_fd);
print_blanks(1);
column++;
(void)putc('/',dcl_fd);
column++;
if (!DECLARE_COMPACT())
{
print_blanks(1);
column++;
}
len = 0;
if (strcmp(name,blank_com_name) != 0) {
for (p=name; *p; ++p, ++len)
(void)putc(VARIABLES_AND_CONSTANTS_LOWERCASE() ?
makelower(*p) : makeupper(*p),dcl_fd);
}
column += len;
if (!DECLARE_COMPACT())
{
if (len <= 6) /* Max standard length */
{
print_blanks(7-len); /* Print padding */
column += 7-len;
}
}
(void)putc('/',dcl_fd);
column++;
if (DECLARE_COMPACT())
{
print_blanks(1);
column++;
}
else if (column < FIRST_VARIABLE_COLUMN)
{
print_blanks(FIRST_VARIABLE_COLUMN-column);
column = FIRST_VARIABLE_COLUMN;
}
else if (column == FIRST_VARIABLE_COLUMN)
{
print_blanks(1);
column++;
print_blanks(NEXT_COLUMN(column)-column);
column = NEXT_COLUMN(column);
}
else
{
print_blanks(NEXT_COLUMN(column)-column);
column = NEXT_COLUMN(column);
}
return column;
}
PRIVATE void
print_declaration_class(sym_list, n, header)
Lsymtab *sym_list[];
int n;
char *header;
{
int t;
static int type_table[] = /* table defining output declaration order */
{ /* (alphabetical by type name) */
type_STRING,
type_COMPLEX,
type_DCOMPLEX,
type_DP,
type_INTEGER,
type_LOGICAL,
type_REAL,
};
if (n > 0)
{
for (t = 0; t < sizeof(type_table)/sizeof(type_table[0]); ++t)
print_selected_declarations(sym_list, n, type_table[t],
(char*)NULL, &header);
}
}
PRIVATE void
print_one_list_decls(sym_entry, list_type_name, pheader, pnd)
Lsymtab *sym_entry;
char *list_type_name;
char **pheader;
int *pnd;
{
int column, need, next_column, nv;
int ncontin;
int h;
Token *t;
Lsymtab *symt;
char *p;
column = 0;
ncontin = 0; /* count of continuation lines */
nv = 0; /* count of variables in statement */
for(t = sym_entry->src.toklist->tokenlist;
t != NULL;
t = t->next_token)
{ /* Loop over members */
h = t->value.integer;
symt = hashtab[h].loc_symtab;
if (column == 0) /* at beginning of line, so */
{ /* we need a type name */
maybe_print_module_header();
if ((*pheader != (char*)NULL) &&
(strcmp(list_type_name,"COMMON") != 0))
{ /* print header only once */
(void)fprintf(dcl_fd,"%c %s\n", comment_char,*pheader);
print_empty_comment_line();
*pheader = (char*)NULL; /* so we don't print it again */
}
column = print_list_name(list_type_name,sym_entry->name);
nv = 0; /* no variables yet in statement */
ncontin = 0;
++(*pnd); /* count declarations produced */
}
if (DECLARE_COMPACT())
next_column = (nv==0?column:column + 2);
else
next_column = NEXT_COLUMN(nv==0?column:column + 2);
need = (int)strlen(symt->name);
if ((next_column + need) > 72) /* then must start new line */
{
(void)putc('\n',dcl_fd);
if (nv>0 && (strcmp(list_type_name,"COMMON") == 0) &&
(NO_CONTINUATION_LINES() || ncontin == 19))
{
column = print_list_name(list_type_name,sym_entry->name);
nv = 0; /* no variables yet in statement */
ncontin = 0;
}
else
{
print_blanks(5);
(void)putc('x',dcl_fd);
column = 6;
if (DECLARE_COMPACT())
next_column = (nv==0?column:column + 2);
else
next_column = NEXT_COLUMN(nv==0?column:column + 2);
++ncontin;
}
}
if (nv > 0) /* multiple variables */
{
(void)fputs(", ",dcl_fd);
print_blanks(next_column - column - 2);
column = next_column;
}
for (p = symt->name; *p; ++p)
(void)putc(VARIABLES_AND_CONSTANTS_LOWERCASE() ?
makelower(*p) : makeupper(*p),dcl_fd);
column += need;
nv++; /* count variables */
}
if ((nv > 0) && (strcmp(list_type_name,"COMMON") == 0))
{
if (column > 0)
(void)putc('\n',dcl_fd);
print_empty_comment_line();
column = 0;
}
if (column > 0)
(void)putc('\n',dcl_fd);
}
PRIVATE void
print_parameter_statement(symt)
Lsymtab *symt;
{
int column;
int need;
int i;
column = print_type_name(type_ERROR,"PARAMETER",0,symt);
need = strlen(get_parameter_value(symt));
if ((column + need) > 72) /* then too long to fit on current line */
{
(void)fputs("\n x",dcl_fd);
column = 6;
if ((column + need) > 72)
{ /* long parameter setting requires line break */
for (i = 0; stmt_fragment[i]; ++i)
{
if (column == 72)
{
(void)fputs("\n x",dcl_fd);
column = 6;
}
(void)putc((int)stmt_fragment[i],dcl_fd);
column++;
}
}
else
(void)fputs(stmt_fragment,dcl_fd);
}
else /* fits on current line */
(void)fputs(stmt_fragment,dcl_fd);
(void)putc('\n',dcl_fd);
}
PRIVATE void
print_selected_declarations(sym_list, n, the_type, type_name, pheader)
Lsymtab *sym_list[];
int n;
int the_type;
char *type_name;
char **pheader;
{
int column, i, last_size, need, next_column, nt, nv, ncontin,
raw_type, sym_type, sym_size;
char *p;
column = 0;
last_size = 0;
nt = 0; /* count of type declaration stmts */
nv = 0; /* count of variables in statement */
for (i = 0; i < n; ++i)
{ /* loop over variables */
raw_type = datatype_of(sym_list[i]->type);
if (DECLARE_ONLY_UNDECLARED())
{
if (raw_type != type_UNDECL)
continue; /* want declarations only for undeclared vars */
if (sym_list[i]->external) /* and not for explicit EXTERNAL */
continue;
if (sym_list[i]->intrinsic) /* and not for explicit INTRINSIC */
continue;
}
sym_type = (raw_type == type_UNDECL) ?
get_type(sym_list[i]) : datatype_of(sym_list[i]->type);
if ((the_type != type_ERROR) && (sym_type != the_type))
continue;
sym_size = ACTUAL_SIZE(sym_list[i]);
if ((nv > 0) && (sym_size != last_size))
{ /* have new length modifier, so must start new declaration */
(void)putc('\n',dcl_fd);
nt++; /* count type declaration statements */
column = 0;
ncontin = 0;
nv = 0;
}
if (column == 0) /* at beginning of line, so */
{ /* we need a type name */
maybe_print_module_header();
if (*pheader != (char*)NULL)
{ /* print header only once */
(void)fprintf(dcl_fd,"%c %s\n",comment_char,*pheader);
print_empty_comment_line();
*pheader = (char*)NULL; /* so we don't print it again */
}
column = print_type_name(the_type,type_name, sym_size,
sym_list[i]);
last_size = sym_size;
nv = 0; /* no variables yet in statement */
ncontin = 0;
}
if (DECLARE_COMPACT())
next_column = (nv==0?column:column + 2);
else
next_column = NEXT_COLUMN(nv==0?column:column + 2);
need = (int)strlen(sym_list[i]->name);
if (sym_list[i]->array_var) /* leave space for "(...)" */
need += strlen(get_dimension_list(sym_list[i]));
if ((next_column + need) > 72) /* then must start new declaration */
{
(void)putc('\n',dcl_fd);
nt++; /* count type declaration statements */
if (nv>0 && (NO_CONTINUATION_LINES() || ncontin == 19))
{
column = print_type_name(the_type,type_name, sym_size,
sym_list[i]);
ncontin = 0;
nv = 0; /* no variables yet in statement */
}
else
{
print_blanks(5);
(void)putc('x',dcl_fd);
column = 6;
if (DECLARE_COMPACT())
next_column = (nv==0?column:column + 2);
else
next_column = NEXT_COLUMN(nv==0?column:column + 2);
++ncontin;
}
last_size = sym_size;
}
if (nv > 0) /* multiple variables */
{
(void)fputs(", ",dcl_fd);
print_blanks(next_column - column - 2);
column = next_column;
}
for (p = sym_list[i]->name; *p; ++p)
(void)putc(VARIABLES_AND_CONSTANTS_LOWERCASE() ?
makelower(*p) : makeupper(*p),dcl_fd);
if (sym_list[i]->array_var)
(void)fputs(stmt_fragment,dcl_fd);
column += need;
nv++; /* count variables */
if (sym_list[i]->parameter)
{
(void)putc('\n',dcl_fd);
print_parameter_statement(sym_list[i]);
column = 0;
nt++;
nv = 0;
}
}
if (column > 0)
{
(void)putc('\n',dcl_fd);
nt++; /* count type declaration statements */
}
if (nt > 0)
print_empty_comment_line();
}
PRIVATE int
print_type_name(the_type,type_name,the_size,symt)
int the_type; /* type_ERROR if type_name non-NULL */
char *type_name; /* non-NULL overrides type_table[] use */
int the_size;
Lsymtab *symt;
{ /* return value is last column printed */
int column;
char digits[sizeof("*18446744073709551616")]; /* big enough for 2^64 */
char *p;
char *size_expression;
maybe_print_module_header();
print_blanks(6);
column = 6;
for (p = (type_name == (char*)NULL) ? type_table[the_type] : type_name;
*p; ++p, ++column)
(void)putc(KEYWORDS_LOWERCASE() ? makelower(*p) : makeupper(*p),
dcl_fd);
if (symt != NULL) {
if (((symt->size_is_adjustable && (the_type == type_STRING))) ||
(the_size == size_ADJUSTABLE)) /* happens only for CHARACTER*(*) */
{
/* size_is_adjustable overrides the_size because def_parameter() */
/* in symtab.c replaced size_ADJUSTABLE with actual size. */
(void)fputs("*(*)",dcl_fd);
column += 4;
}
else if (symt->size_is_expression && (the_type == type_STRING))
{
size_expression = get_size_expression(symt);
(void)fputs(size_expression,dcl_fd);
column += strlen(size_expression);
}
else if ((the_size > 0) &&
(the_type != type_ERROR) &&
(the_size != std_size[the_type]))
{ /* supply length modifier for non-standard type sizes */
(void)sprintf(digits,"*%d",the_size);
(void)fputs(digits,dcl_fd);
column += strlen(digits);
}
}
if (DECLARE_COMPACT())
{
print_blanks(1);
column++;
}
else if (column < FIRST_VARIABLE_COLUMN)
{
print_blanks(FIRST_VARIABLE_COLUMN-column);
column = FIRST_VARIABLE_COLUMN;
}
else if (column == FIRST_VARIABLE_COLUMN)
{
print_blanks(1);
column++;
print_blanks(NEXT_COLUMN(column)-column);
column = NEXT_COLUMN(column);
}
else
{
print_blanks(NEXT_COLUMN(column)-column);
column = NEXT_COLUMN(column);
}
return (column);
}
PRIVATE int
select_arguments(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is a module argument) */
if (sym_entry->declared_external ||
sym_entry->invoked_as_func)
return (0);
else if (sym_entry->argument)
return (1);
else
return (0);
}
PRIVATE int
select_commons(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is in a COMMON block) */
if (sym_entry->common_var)
return (1);
else
return (0);
}
PRIVATE int
select_externals_by_name(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is external and must appear in EXTERNAL declaration) */
if (sym_entry->declared_intrinsic) /* must appear first, because symbols */
return (0); /* can be both declared_intrinsic and declared_external*/
/* ??? is this a bug in ftnchek 2.7 ??? */
else if (storage_class_of(sym_entry->type) == class_STMT_FUNCTION)
return (0);
else if (sym_entry->declared_external)
return (1);
else if (sym_entry->declared_intrinsic || sym_entry->intrinsic)
return (0);
else if (sym_entry->invoked_as_func)
return (1);
else
return (0);
}
PRIVATE int
select_externals_by_type(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is external and must appear in a type declaration) */
if (storage_class_of(sym_entry->type) == class_STMT_FUNCTION)
return (0);
else if (sym_entry->declared_external)
return (1);
else if (sym_entry->declared_intrinsic)
return (0);
else if (sym_entry->intrinsic)
{
if (datatype_of(sym_entry->type) == type_UNDECL)
{ /* user provided no type declaration */
if ((sym_entry->info.intrins_info)->result_type == type_GENERIC)
return (0); /* generics CANNOT have explicit type */
else
return (1); /* not generic, so has explicit type */
}
else /* user supplied an explicit type */
return (1);
}
else if (sym_entry->invoked_as_func)
return (1);
else
return (0);
}
PRIVATE int
select_intrinsics_by_name(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is intrinsic and must appear in INTRINSIC declaration) */
if (sym_entry->declared_intrinsic)
return (1);
else
return (0);
}
PRIVATE int
select_intrinsics_by_type(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is intrinsic and must appear in a type declaration) */
if (sym_entry->intrinsic &&
((sym_entry->info.intrins_info)->result_type == type_GENERIC))
return (0);
else
return (select_intrinsics_by_name(sym_entry));
}
PRIVATE int
select_locals(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is a local variable) */
if (SF3_DECLARATIONS() && sf3_internal_name(sym_entry))
return (0);
else if (sym_entry->argument ||
sym_entry->common_var ||
sym_entry->declared_external ||
sym_entry->declared_intrinsic ||
sym_entry->entry_point ||
sym_entry->external ||
sym_entry->intrinsic ||
sym_entry->invoked_as_func ||
sym_entry->parameter)
return (0);
else
return (1);
}
PRIVATE int
select_common_blocks(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is a COMMON block name) */
if (storage_class_of(sym_entry->type) == class_COMMON_BLOCK)
return (1);
else
return (0);
}
PRIVATE int
select_namelists(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is a NAMELIST name) */
if (storage_class_of(sym_entry->type) == class_NAMELIST)
return (1);
else
return (0);
}
PRIVATE int
select_parameters(sym_entry)
Lsymtab *sym_entry;
{
/* return (symbol is a PARAMETER name) */
if (sym_entry->parameter)
return (1);
else
return (0);
}
PRIVATE int
select_statement_functions(sym_entry)
Lsymtab *sym_entry;
{
if (storage_class_of(sym_entry->type) == class_STMT_FUNCTION)
return (1);
else
return (0);
}
PRIVATE int
sf3_internal_name(sym_entry)
Lsymtab *sym_entry;
{ /* Return (symbol is an SFTRAN3 internal name). */
char *p = sym_entry->name;
/* The SFTRAN3 preprocessor uses internal names of the form NPRddd,
NXdddd, N2dddd, and N3dddd, where d is a decimal digit. */
if ((p[0] != 'N') || (strlen(p) != 6))
return (0);
switch (p[1])
{
case 'P':
if ((p[2] == 'R') && isdigit(p[3]) && isdigit(p[4]) && isdigit(p[5]))
return (1);
else
return (0);
case 'X': /* fall through */
case '2': /* fall through */
case '3':
if (isdigit(p[2]) && isdigit(p[3]) && isdigit(p[4]) && isdigit(p[5]))
return (1);
else
return (0);
default:
return (0);
}
}