home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD2.mdf
/
c
/
tools
/
crossref
/
cref
/
cref.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-11-25
|
15KB
|
494 lines
/* CREF - C cross-reference utility
Author: Jeff Taylor, The Toolsmith (c) copyright 1982, 1985.
Environment: C; UNIX 4.2 BSD.
Algorithms:
Modified algorithm T from "The Art of Computer Programming," Vol. 1,
p. 317, by D.E.Knuth used in tree_walk().
History:
22 November 1982 - removed recursion from lookup().
16 December 1982 - remove recursion from tree_walk().
26 March 1985 - port to DECUS C.
27 March 1985 - line # list made a circular queue: insert(), list_file().
reserved word search changed to binary search: keyword().
28 March 1985 - port to UNIX 4.2 BSD.
*/
/* start of new comment block */
/* MORE CODING HISTORY (and the beat goes on) */
/* Coding History --------------------------------------------------------| */
/* | Date | Who | What | */
/* |==========|=====|=====================================================| */
/* | 11/23/88 | KRG | Transcribed from Dr. Dobbs' TOOLBOOK OF C, with | */
/* | | | minimum modifications as required for porting to | */
/* | | | MicroSoft C 5.1 (5.0 okay, too) | */
/* |----------|-----|-----------------------------------------------------| */
/* | 11/25/88 | KRG | Added some formatting to output (list_file()). | */
/* |----------|-----|-----------------------------------------------------| */
/* | 11/26/88 | KRG | Completed slightly lacking keyword list (oops). | */
/* |----------|-----|-----------------------------------------------------| */
/* | / / | | | */
/* |----------|-----|-----------------------------------------------------| */
/* end of new comment block */
#include <stdio.h>
#include <ctype.h>
#include <malloc.h> /* 881123 KRG */
#include <string.h> /* 881123 KRG */
#include "style.h"
#define lower(c) (isupper(c)? tolower(c) : (c))
#define streq(a, b) (strcmp(a, b) == 0)
#define WIDTH 80 /* width of output device */
struct instance
{
struct instance *next;
int line;
};
union ptr
{
struct node *files;
struct instance *lines;
};
struct node
{
struct node *right, *left;
union ptr p;
char *name;
};
struct node *symbol_root = NULL;
struct node *file_root= NULL;
int line_count = 0;
#define ID 'a' /* identifier */
#define INTEGER '0' /* integer */
/************************************
* Symbol Table handling routines *
***********************************/
/* lookup - install name at or below root */
struct node **lookup (root, name)
/*register*/ struct node **root;
/*register*/ char *name;
{
register int cond;
#ifdef RECURSIVE
if (*root != NULL)
{
if ((cond = lexcmp(name, (*root)->name)) != 0)
root = lookup((cond < 0)? &(*root)->left : &(*root)->right,
name);
}
#else
while (*root != NULL && (cond = lexcmp(name, (*root)->name)))
root = (cond < 0)? &(*root)->left : &(*root)->right;
#endif
return(root);
}
/* add - insert entry for "name" in tree at "root" */
struct node *add (name)
char *name;
{
/* char *malloc(); */
register struct node *r;
r = (struct node *) malloc(sizeof(struct node));
r->left = r->right = NULL;
r->p.lines = NULL;
r->name = name;
return (r);
}
/* tree_walk - call 'ftn' for each node in inorder */
void tree_walk (root, ftn)
/*register*/ struct node *root;
/*register*/ void (*ftn)();
{
#ifdef RECURSIVE
if (root != NULL)
{
tree_walk(root->left, ftn);
(*ftn)(root);
tree_walk(root->right, ftn);
}
#else
register struct node *stack, *tmp;
stack = NULL; /* stack initially empty */
for ( ; ; )
{
if (root != NULL)
{
tmp = root;
root = root->left; /* move to left */
tmp->left = stack;
stack = tmp; /* push tmp */
}
else if (stack != NULL) /* stack not empty */
{
root = stack;
stack = stack->left; /* pop */
(*ftn)(root); /* visit node */
root = root->right; /* move right */
}
else
break; /* stack is empty */
}
#endif
}
/* insert - add 'line_no' to the circular list, 'origin' */
struct instance *insert (origin, line_no)
/*register*/ struct instance *origin;
int line_no;
{
/* char *malloc(); */
register struct instance *t;
if (origin == NULL || origin->line != line_no)
{
t = (struct instance *)malloc(sizeof(struct instance));
if (origin == NULL)
origin = t;
t->line = line_no;
t->next = origin->next;
origin->next = t;
origin = t;
}
return (origin);
}
/* use - log an occurrence of "name" in "file" at "line" */
void use (name, file, line)
char *name, *file;
int line;
{
char *newcpy();
register struct node **ft, **nt;
if (*(nt = lookup(&symbol_root, name)) == NULL)
*nt = add(newcpy(name));
if (*(nt = lookup(&((*nt)->p.files), file)) == NULL)
{
if (*(ft = lookup(&file_root, file)) == NULL)
*ft = add(newcpy(file));
*nt = add((*ft)->name);
}
(*nt)->p.lines = insert((*nt)->p.lines, line);
}
/* get_name -extract file name from line */
void get_name (line, file)
/*register*/ char *line;
char *file;
{
void copy_until();
register char *delim;
while (*line == ' ' || *line == '\t')
++line;
if (*line != '\n') /* if none, use "file" as is */
{
if (*line == '"')
{
delim = "\"\n";
++line;
}
else if (*line == '<')
{
delim = ">\n";
++line;
}
else
delim = "\t\n";
copy_until(file, line, delim);
}
}
/* new_line - return pointer to the next line */
char *new_line()
{
static char line[MAXLINE+1];
++line_count;
return(fgets(line, MAXLINE, stdin));
}
/* white_space - tests for blanks, tabs and comments */
/* NOTE: \n is NOT counted as 'white space' in this program; it is used as
a token class. 881125 KRG */
boolean white_space(s)
/*register*/ char **s;
{
if (**s == ' ' || **s == '\t')
return(TRUE);
if (**s == '/' && *(*s+1) == '*') /* comment */
{
while (*++*s != '/')
{
while (*++*s != '*')
{
if (**s == EOS)
{
if ((*s = new_line()) != NULL)
--*s; /* because of pre-increment of inner loop */
else
{
fprintf(stderr, "unexpected EOF\n");
return (FALSE);
}
}
}
}
return (TRUE);
}
return(FALSE);
}
/* ishex - is 'c' a hexadecimal digit? */
boolean ishex(c)
/*register*/ char c;
{
return (isxdigit(c));
}
/* get_token - strip leading token from s */
char get_token(s, t)
/*register*/ char **s, *t;
{
char esc();
register char class;
while (white_space(s))
++*s;
if (isalpha(**s) || **s == '_') /* identifier */
{
class = ID;
do
*t++ = *(*s)++;
while (isdigit(**s) || isalpha(**s) || **s == '_');
}
else if (**s == '\"' || **s == '\'') /* string or literal */
{
class = **s;
do
{
esc(s);
++*s;
if (**s == EOS)
{
if ((*s = new_line()) == NULL)
goto out; /* aaaargh! KRG */
}
}
while (**s != class);
++*s;
}
else if (isdigit(**s))
{
do
{
class = *++*s;
class = lower(class);
}
while (ishex(class) || class == 'x' || class == 'l' || class == '.');
class = INTEGER;
}
else
class = *(*s)++;
out:
*t = EOS;
return(class);
}
static char *reserved[] =
{
"auto", "break", "case", "char", "const", "continue", "default", "do",
"double", "else", "enum", "extern", "float", "for", "goto", "if", "int",
"long", "register", "return", "short", "signed", "sizeof", "static",
"struct", "switch", "typedef", "union", "unsigned", "void", "volatile",
"while"
};
/* keyword - is "s" a reserved word in C */
boolean keyword (s)
char *s;
{
register int cond; /* condition code of lexcmp */
register int mid;
int hi, lo;
/* binary search; reserved[] must be in alphabetical order */
lo = 0; hi = sizeof(reserved) / sizeof(char *) - 1;
while (lo <= hi)
{
mid = (hi + lo) / 2;
if ((cond = lexcmp(s, reserved[mid])) == 0)
return(TRUE);
if (cond < 0)
hi = mid - 1;
else
lo = mid + 1;
}
return (FALSE);
}
/* xref - cross reference */
void xref(file)
/*register*/ char *file;
{
/* int atoi(); */
register char class;
char *s, token[MAXLINE+1];
line_count = 0;
while ((s = new_line()) != NULL)
{
if ((class = get_token(&s, token)) != '#')
{
while (class != '\n')
{
if (class == ID && !keyword(token))
use(token, file, line_count);
class = get_token(&s, token);
}
}
else if (get_token (&s, token) == ID)
{
if (streq(token, "include"))
{
get_name(s, token);
use(token, file, line_count);
}
else if (streq(token, "define"))
{
get_token(&s, token);
use(token, file, line_count);
while (class != '\n') /* 881125 KRG; This is to */
class = get_token(&s, token); /* take care of comments */
/* starting on the same */
/* line as a #define, */
/* like above. */
}
else if (streq(token, "ifdef") || streq(token, "ifndef"))
{
get_token(&s, token);
use(token, file, line_count);
}
else if (streq(token, "line"))
{
if (get_token(&s, token) == INTEGER)
line_count = atoi(token);
else
fprintf(stderr, "#line %s\n", token);
}
else
; /* ignore #else, #endif, etc. */
}
}
}
/* putp - output a partial line to stdout */
unsigned putp(s)
/*register*/ char *s;
{
register unsigned n;
for (n = 0; *s != EOS; ++n)
putchar(*s++);
return(n);
}
/* list_file - print lines within a file */
#define FNAMELEN 14 /* max UNIX filename length. KRG */
#define MAGIC 18 /* numbers are bad, but 18 = 4 + 14; 4 for left
margin, 14 for max UNIX filename length. KRG */
void list_file(ft)
/*register*/ struct node *ft;
{
char *itoa();
register unsigned b;
register struct instance *it;
char buf[5];
char margin[MAGIC + 1]; /* makes it easier to prints formatted
things with the putp() function. KRG */
b = putp(" ");
sprintf(margin,"%-*s", FNAMELEN, ft->name);
b += putp(margin);
/* print line numbers */
it = ft->p.lines = ft->p.lines->next; /* move 'lines' to start */
do
{
if (b == 0)
{
memset(margin, ' ', sizeof(margin));
margin[MAGIC] = EOS;
b = putp(margin);
}
b += putp(" ");
/* b += itoa(it->line, buf) - buf; */ /* <- old line */
b += strlen(itoa(it->line, buf, 10)); /* <- new line */ /* [1] */
putp(buf);
if (b > WIDTH - 8) /* leave margin on right */
{
putp("\n");
b = 0;
}
it = it->next;
}
while (it != ft->p.lines);
if (b > 6) /* non-blank line */
putp("\n");
}
/* print_xref - dump cross reference table to stdout */
void print_xref(nt)
struct node *nt;
{
putp("\n"); putp(nt->name); putp("\n");
tree_walk(nt->p.files, list_file);
}
main (argc, argv)
/*register*/ int argc;
/*register*/ char **argv;
{
/* FILE *freopen(); */
if (argc <= 1)
xref("<stdin>");
else
{
while (--argc > 0)
{
if (freopen(*++argv, "r", stdin) == NULL)
fprintf(stderr, "can't open %s\n", *argv);
else
xref(*argv);
}
}
tree_walk(symbol_root, print_xref);
}
/* [1] itoa() differs from the function in strcref.c by the last parameter;
Microsoft requires the last argument to specify the radix of the function.
Also, Taylor's itoa returned the pointer to the END of the string, not the
beginning, so strlen() had to come to the rescue.
*/