home *** CD-ROM | disk | FTP | other *** search
- /*
- * Simple 'C' cross reference listing generator
- *
- * This program generates a line-numbered listing of a 'C' program, with
- * A cross reference table of all global symbols showing their definition,
- * and any references to them.
- *
- * The program does minimal parsing of the 'C' code, and as such has the
- * following limitations:
- *
- * - The first time a symbol is encountered outside of a function definition
- * is considered to be its definition. This is usually the case, however for
- * symbols #defined in external header files etc, which are used in the
- * definition of other global entities, the first use is considered the
- * definition.
- *
- * - Local symbols having names which are identical to a global symbol are
- * reported as references.
- *
- * - Symbols not defined in the file which don't have an explict "extern"
- * declaration are not reported. To track library functions etc. which
- * fall into this catagory, place an "extern int func()" declaration at
- * the start of the file.
- *
- * Copyright 1993-1994 Dave Dunfield
- * All rights reserved.
- *
- * Permission granted for personal (non-commercial) use only.
- *
- * Compile command: cc ccref -fop
- */
- #include <stdio.h>
-
- #define SYMBOLS 500 /* Maximum number of symbols */
- #define SYMBOL_POOL 5000 /* String space for symbol storage */
- #define REFERENCES 10000 /* Maximum number of references */
-
- /* Symbol table and associated management variables */
- char symbol_pool[SYMBOL_POOL], *symbol_names[SYMBOLS];
- int references[REFERENCES], ref_list[SYMBOLS], pool_top = 0, name_top = 0,
- ref_top = 0;
-
- /* Command line switch variables */
- char list = -1, filename[66];
- int page_width = 79, page_length = 60, tab_size = 4;
-
- /* Misc. housekeeping variables */
- char in_string = 0, in_comment = 0, *optr, pass = 0;
- int bracket = 0, line_number, page_number = 0, pcount = 9999;
-
- /* Table of MICRO-C reserved words */
- char *reserved_words[] = {
- "int", "unsigned", "char", "static", "extern", "register", "struct",
- "union", "if", "else", "while", "do", "for", "switch", "case",
- "default", "return", "break", "continue", "goto", "sizeof",
- "asm", "#define", "#ifdef", "#ifndef", "#else", "#endif",
- "#undef", "#forget", 0 }; /* end of table */
-
- /*
- * Main program
- */
- main(argc, argv)
- int argc;
- char *argv[];
- {
- int i, j, k, l;
- char buffer[200], symbol[50], *sptr, c, last_def;
- FILE *fp;
-
- if(argc < 2)
- abort("\nUse: CCREF <filename> [-list p=page_length t=tab_size w=page_width]\n\nCopyright 1993-1994 Dave Dunfield\nAll rights reserved.\n");
-
- sptr = argv[1];
- i = j = 0;
- do {
- if((filename[i++] = c = toupper(*sptr++)) == '.')
- j = -1; }
- while(c);
- if(!j) {
- filename[i-1] = '.';
- filename[i] = 'C';
- filename[i+1] = 0; }
- fp = fopen(filename, "rvq");
-
- for(i=2; i < argc; ++i) {
- sptr = argv[i];
- switch((toupper(*sptr++) << 8) | toupper(*sptr++)) {
- case 'W=' : /* Specify page width */
- page_width = atoi(sptr);
- break;
- case 'T=' : /* Specify tab size */
- tab_size = atoi(sptr);
- break;
- case 'P=' : /* Specify page length */
- page_length = atoi(sptr);
- break;
- case '-L' : /* Inhibit line numbered listing */
- list = 0;
- break;
- default:
- printf("Invalid argument: %s\n", argv[i]);
- exit(-1); } }
-
- again:
- line_number = 0;
- while(fgets(optr = buffer, sizeof(buffer)-1, fp)) {
- ++line_number;
- if(list && !pass) {
- title("Program Listing");
- printf("%5u ", line_number);
- i = 0;
- while(c = *optr++) {
- if(c == '\t') { /* tab */
- if((i + tab_size) > (page_width - 6)) {
- putc('\n', stdout);
- title("Program Listing");
- printf(" ");
- i = 0; }
- do
- putc(' ', stdout);
- while(++i % tab_size); }
- else {
- if(++i > (page_width - 6)) {
- putc('\n', stdout);
- title("Program Listing");
- printf(" ");
- i = 0; }
- putc(c, stdout); } }
- putc('\n', stdout);
- optr = buffer; }
- if(strbeg(buffer, "#include"))
- continue;
- do {
- if(in_string) switch(c = *optr) {
- default:
- if(c == in_string)
- in_string = 0;
- continue;;
- case '\\' :
- ++optr;
- continue; }
- if(in_comment) switch(c = *optr) {
- case '/' :
- if(*(optr+1) == '*') {
- ++optr;
- ++in_comment; }
- continue;
- case '*' :
- if(*(optr+1) == '/') {
- ++optr;
- --in_comment; }
- default:
- continue; }
- switch(c = *optr) {
- case '{' :
- ++bracket;
- continue;
- case '}' :
- --bracket;
- continue;
- case '/' :
- if(*(optr+1) == '*') {
- in_comment = 1;
- ++optr; }
- continue;
- case '(' :
- if(last_def == 1) {
- in_string = '{';
- ++bracket; }
- continue;
- case '\'' :
- case '\"' :
- in_string = c;
- continue;
- case ' ' :
- case '\t' :
- continue; }
- last_def = 0;
- if(issymbol(c)) {
- sptr = symbol;
- while(issymbol(*optr) || isdigit(*optr))
- *sptr++ = *optr++;
- *sptr = 0;
- --optr;
- for(i=0; sptr = reserved_words[i]; ++i)
- if(!strcmp(symbol, sptr))
- goto skip_symbol;
- if(bracket) {
- if(pass)
- reference(symbol); }
- else {
- if(!pass)
- define(symbol);
- last_def = 1; }
- skip_symbol: } }
- while(*optr++); }
- if(!pass) {
- pass = 1;
- rewind(fp);
- ref_list[name_top] = ref_top;
- goto again; }
- fclose(fp);
-
- pcount = 9999;
- title("Cross Reference");
- printf(" Symbol Def References\n");
- title("Cross Reference");
- printf("--------------- ----- ");
- for(l=22; l < page_width; ++l)
- putc('-', stdout);
- putc('\n', stdout);
-
- for(;;) {
- i = 0;
- while(!symbol_names[i])
- if(++i >= name_top)
- return;
- for(j=i+1; j < name_top; ++j)
- if((sptr = symbol_names[j]) && (strcmp(sptr, symbol_names[i]) < 0))
- i = j;
- title("Cross Reference");
- printf("%-15s %-5u", symbol_names[i], references[j = ref_list[i]]);
- k = ref_list[i+1]-1;
- l = 0;
- while(j < k) {
- if((l += 6) > (page_width-21)) {
- l = 6;
- printf("\n%-21s", ""); }
- printf(" %5u", references[++j]); }
- putc('\n', stdout);
- symbol_names[i] = 0; }
- }
-
- /*
- * Test for valid 'C' symbol character.
- * Also allow '#', so that we can detect '#' directives. This should
- * not conflict with 'C' source since '#' is otherwise not permitted.
- */
- issymbol(c)
- int c;
- {
- return ((c >= 'a') && (c <= 'z'))
- || ((c >= 'A') && (c <= 'Z'))
- || (c == '_')
- || (c == '#');
- }
-
- /*
- * Lookup a symbol in the symbol table
- */
- lookup(symbol)
- char *symbol;
- {
- int i;
- for(i=0; i < name_top; ++i)
- if(!strcmp(symbol_names[i], symbol))
- return i;
- return -1;
- }
-
- /*
- * Log a symbol reference
- */
- reference(symbol)
- char *symbol;
- {
- int s, i, j;
-
- /* Check that symbol defined */
- if((s = lookup(symbol)) == -1)
- return;
-
- /* Check that line not already reported */
- j = ref_list[s+1];
- for(i=ref_list[s]+1; i < j; ++i)
- if(references[i] == line_number)
- return;
-
- /* Expand reference list to include new number */
- if(ref_top >= REFERENCES)
- error("Reference table full");
- for(i = ref_top++; i > j; --i)
- references[i] = references[i-1];
-
- /* Adjust other symbols */
- for(i=s+1; i <= name_top; ++i)
- ++ref_list[i];
-
- references[j] = line_number;
- }
-
- /*
- * Define a new symbol
- */
- define(symbol)
- char *symbol;
- {
- if(lookup(symbol) != -1) {
- reference(symbol);
- return; }
-
- if(name_top >= SYMBOLS)
- error("Symbol table full");
- symbol_names[name_top] = &symbol_pool[pool_top];
- ref_list[name_top++] = ref_top;
- do {
- if(pool_top >= SYMBOL_POOL)
- error("Symbol name space exausted");
- symbol_pool[pool_top++] = *symbol; }
- while(*symbol++);
- references[ref_top++] = line_number;
- }
-
- /*
- * Write title for page
- */
- title(string)
- char *string;
- {
- if(++pcount >= page_length) {
- if(page_number)
- putc('\f', stdout);
- printf("%-30s %-30s Page: %u\n\n", filename, string, ++page_number);
- pcount = 2; }
- }
-
- /*
- * Report an error in the file
- */
- error(string)
- char *string;
- {
- fprintf(stdout, "Error in line %u : %s\n", line_number, string);
- exit(-1);
- }
-