#include #include #include #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE (!0) #endif typedef struct scrap_node { struct scrap_node *next; int scrap; } Scrap_Node; typedef struct name { char *spelling; struct name *llink; struct name *rlink; Scrap_Node *defs; Scrap_Node *uses; int mark; char tab_flag; char indent_flag; char debug_flag; } Name; int tex_flag; /* if FALSE, don't emit the .tex file */ int output_flag; /* if FALSE, don't emit the output files */ int compare_flag; /* if FALSE, overwrite without comparison */ char *command_name; char *source_name; /* name of the current file */ int source_line; /* current line in the source file */ Name *file_names; Name *macro_names; Name *user_names; void pass1(); void write_tex(); void write_files(); void source_open(); /* pass in the name of the source file */ int source_get(); /* no args; returns the next char or EOF */ void init_scraps(); int collect_scrap(); int write_scraps(); Name *collect_file_name(); Name *collect_macro_name(); Name *collect_scrap_name(); Name *name_add(); Name *prefix_add(); char *save_string(); void reverse_lists(); void *arena_getmem(); void arena_free(); static void copy_scrap(); /* formats the body of a scrap */ static void print_scrap_numbers(); /* formats a list of scrap numbers */ static void format_entry(); /* formats an index entry */ static void format_user_entry(); void write_tex(file_name, tex_name) char *file_name; char *tex_name; { FILE *tex_file = fopen(tex_name, "w"); if (tex_file) { source_open(file_name); { int scraps = 1; int c = source_get(); while (c != EOF) { if (c == '@') { int big_definition = FALSE; c = source_get(); switch (c) { case 'O': big_definition = TRUE; case 'o': { Name *name = collect_file_name(); { fputs("\\begin{flushleft}\n", tex_file); if (!big_definition) fputs("\\begin{minipage}{\\linewidth}\n", tex_file); } fprintf(tex_file, "\\verb@\"%s\"@", name->spelling); fprintf(tex_file, " {\\footnotesize %d }$\\equiv$\n", scraps++); { fputs("\\vspace{-1.5ex}\n\\begin{quote}\n", tex_file); copy_scrap(tex_file); fputs("$\\Diamond$\n\\end{quote}\n\\vspace{-2ex}\n", tex_file); } { if (name->defs->next) { fputs("{\\footnotesize File defined by scraps ", tex_file); print_scrap_numbers(tex_file, name->defs); fputs("}\n", tex_file); } } { if (!big_definition) fputs("\\end{minipage}\\\\[4ex]\n", tex_file); fputs("\\end{flushleft}\n", tex_file); do c = source_get(); while (isspace(c)); } } break; case 'D': big_definition = TRUE; case 'd': { Name *name = collect_macro_name(); { fputs("\\begin{flushleft}\n", tex_file); if (!big_definition) fputs("\\begin{minipage}{\\linewidth}\n", tex_file); } fprintf(tex_file, "$\\langle$%s", name->spelling); fprintf(tex_file, " {\\footnotesize %d}$\\rangle\\equiv$\n", scraps++); { fputs("\\vspace{-1.5ex}\n\\begin{quote}\n", tex_file); copy_scrap(tex_file); fputs("$\\Diamond$\n\\end{quote}\n\\vspace{-2ex}\n", tex_file); } { fputs("{\\footnotesize ", tex_file); if (name->defs->next) { fputs("Macro defined by scraps ", tex_file); print_scrap_numbers(tex_file, name->defs); fputs("\\\\[-1ex]\n", tex_file); } } { if (name->uses) { if (name->uses->next) { fputs("Macro referenced in scraps ", tex_file); print_scrap_numbers(tex_file, name->uses); fputs("}\n", tex_file); } else fprintf(tex_file, "Macro referenced in scrap %d.}\n", name->uses->scrap); } else { fputs("Macro never referenced.}\n", tex_file); fprintf(stderr, "%s: <%s> never referenced.\n", command_name, name->spelling); } } { if (!big_definition) fputs("\\end{minipage}\\\\[4ex]\n", tex_file); fputs("\\end{flushleft}\n", tex_file); do c = source_get(); while (isspace(c)); } } break; case 'f': { if (file_names) { fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file); format_entry(file_names, tex_file, TRUE); fputs("\\end{list}", tex_file); } c = source_get(); } break; case 'm': { if (macro_names) { fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file); format_entry(macro_names, tex_file, FALSE); fputs("\\end{list}", tex_file); } c = source_get(); } break; case 'u': { if (user_names) { fputs("\n\\begin{list}{}{\\setlength{\\itemsep}{-\\parsep}}\n", tex_file); format_user_entry(user_names, tex_file); fputs("\\end{list}", tex_file); } c = source_get(); } break; case '@': putc(c, tex_file); default: c = source_get(); break; } } else { putc(c, tex_file); c = source_get(); } } } fclose(tex_file); } else fprintf(stderr, "%s: can't open %s\n", command_name, tex_name); } static void print_scrap_numbers(tex_file, scraps) FILE *tex_file; Scrap_Node *scraps; { fprintf(tex_file, "%d", scraps->scrap); scraps = scraps->next; while (scraps->next) { fprintf(tex_file, ", %d", scraps->scrap); scraps = scraps->next; } fprintf(tex_file, " and~%d.", scraps->scrap); } static void copy_scrap(file) FILE *file; { int indent = 0; int c = source_get(); fputs("\\verb@", file); while (1) { switch (c) { case '@': { c = source_get(); switch (c) { case '@': fputs("@{\\tt @}\\verb@", file); break; case '|': { do { do c = source_get(); while (c != '@'); c = source_get(); } while (c != '}'); } case '}': putc('@', file); return; case '<': { Name *name = collect_scrap_name(); fprintf(file, "@$\\langle$%s {\\footnotesize ", name->spelling); if (name->defs) fprintf(file, "%d", name->defs->scrap); else { putc('?', file); fprintf(stderr, "%s: scrap never defined <%s>\n", command_name, name->spelling); } fputs("}$\\rangle$\\verb@", file); } break; default: /* ignore these since pass1 will have warned about them */ break; } } break; case '\n': fputs("@\\\\\n\\verb@", file); indent = 0; break; case '\t': { int delta = 8 - (indent % 8); indent += delta; while (delta > 0) { putc(' ', file); delta--; } } break; default: putc(c, file); indent++; break; } c = source_get(); } } static void format_entry(name, tex_file, file_flag) Name *name; FILE *tex_file; int file_flag; { while (name) { format_entry(name->llink, tex_file, file_flag); { fputs("\\item \\hspace{-\\leftmargin}", tex_file); if (file_flag) { fprintf(tex_file, "\\verb@\"%s\"@ ", name->spelling); { Scrap_Node *p = name->defs; fputs("{\\footnotesize Defined by scrap", tex_file); if (p->next) { fputs("s ", tex_file); print_scrap_numbers(tex_file, p); } else fprintf(tex_file, " %d.", p->scrap); putc('}', tex_file); } } else { fprintf(tex_file, "$\\langle$%s {\\footnotesize ", name->spelling); { Scrap_Node *p = name->defs; if (p) { while (1) { fprintf(tex_file, "%d", p->scrap); p = p->next; if (!p) break; fputs(", ", tex_file); } } else putc('?', tex_file); } fputs("}$\\rangle$ ", tex_file); { Scrap_Node *p = name->uses; fputs("{\\footnotesize ", tex_file); if (p) { fputs("Referenced in scrap", tex_file); if (p->next) { fputs("s ", tex_file); print_scrap_numbers(tex_file, p); } else fprintf(tex_file, " %d.", p->scrap); } else fputs("Not referenced.", tex_file); putc('}', tex_file); } } putc('\n', tex_file); } name = name->rlink; } } static void format_user_entry(name, tex_file) Name *name; FILE *tex_file; { while (name) { format_user_entry(name->llink, tex_file); { Scrap_Node *uses = name->uses; Scrap_Node *defs = name->defs; fprintf(tex_file, "\\item \\hspace{-\\leftmargin}\\verb@%s@: ", name->spelling); do { if (uses && (!defs || uses->scrap < defs->scrap)) { fprintf(tex_file, "%d", uses->scrap); uses = uses->next; } else if (defs && (!uses || defs->scrap <= uses->scrap)) { if (uses && defs->scrap == uses->scrap) uses = uses->next; fprintf(tex_file, "\\underline{%d}", defs->scrap); defs = defs->next; } if (uses || defs) fputs(", ", tex_file); } while (uses || defs); fputs(".\n", tex_file); } name = name->rlink; } }