summaryrefslogtreecommitdiff
path: root/web/nuweb/msdos/scraps.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /web/nuweb/msdos/scraps.c
Initial commit
Diffstat (limited to 'web/nuweb/msdos/scraps.c')
-rw-r--r--web/nuweb/msdos/scraps.c542
1 files changed, 542 insertions, 0 deletions
diff --git a/web/nuweb/msdos/scraps.c b/web/nuweb/msdos/scraps.c
new file mode 100644
index 0000000000..ecc35ea856
--- /dev/null
+++ b/web/nuweb/msdos/scraps.c
@@ -0,0 +1,542 @@
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#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();
+
+
+#define SLAB_SIZE 500
+
+typedef struct slab {
+ struct slab *next;
+ char chars[SLAB_SIZE];
+} Slab;
+typedef struct {
+ char *file_name;
+ int file_line;
+ Slab *slab;
+} ScrapEntry;
+ScrapEntry *SCRAP[256];
+
+#define scrap_array(i) SCRAP[(i) >> 8][(i) & 255]
+
+int scraps;
+void init_scraps()
+{
+ scraps = 1;
+ SCRAP[0] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+}
+typedef struct {
+ Slab *scrap;
+ int index;
+} Manager;
+static void push(c, manager)
+ char c;
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ scrap->chars[index++] = c;
+ if (index == SLAB_SIZE) {
+ Slab *new = (Slab *) arena_getmem(sizeof(Slab));
+ scrap->next = new;
+ manager->scrap = new;
+ index = 0;
+ }
+ manager->index = index;
+}
+static void pushs(s, manager)
+ char *s;
+ Manager *manager;
+{
+ while (*s)
+ push(*s++, manager);
+}
+int collect_scrap()
+{
+ Manager writer;
+ {
+ Slab *scrap = (Slab *) arena_getmem(sizeof(Slab));
+ if ((scraps & 255) == 0)
+ SCRAP[scraps >> 8] = (ScrapEntry *) arena_getmem(256 * sizeof(ScrapEntry));
+ scrap_array(scraps).slab = scrap;
+ scrap_array(scraps).file_name = save_string(source_name);
+ scrap_array(scraps).file_line = source_line;
+ writer.scrap = scrap;
+ writer.index = 0;
+ }
+ {
+ int c = source_get();
+ while (1) {
+ switch (c) {
+ case EOF: fprintf(stderr, "%s: unexpect EOF in scrap (%s, %d)\n",
+ command_name, scrap_array(scraps).file_name,
+ scrap_array(scraps).file_line);
+ exit(-1);
+ case '@': {
+ c = source_get();
+ switch (c) {
+ case '@': pushs("@@", &writer);
+ c = source_get();
+ break;
+ case '|': {
+ do {
+ char new_name[100];
+ char *p = new_name;
+ do
+ c = source_get();
+ while (isspace(c));
+ if (c != '@') {
+ Name *name;
+ do {
+ *p++ = c;
+ c = source_get();
+ } while (c != '@' && !isspace(c));
+ *p = '\0';
+ name = name_add(&user_names, new_name);
+ if (!name->defs || name->defs->scrap != scraps) {
+ Scrap_Node *def = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ def->scrap = scraps;
+ def->next = name->defs;
+ name->defs = def;
+ }
+ }
+ } while (c != '@');
+ c = source_get();
+ if (c != '}') {
+ fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+ }
+ case '}': push('\0', &writer);
+ return scraps++;
+ case '<': {
+ Name *name = collect_scrap_name();
+ {
+ char *s = name->spelling;
+ int len = strlen(s) - 1;
+ pushs("@<", &writer);
+ while (len > 0) {
+ push(*s++, &writer);
+ len--;
+ }
+ if (*s == ' ')
+ pushs("...", &writer);
+ else
+ push(*s, &writer);
+ pushs("@>", &writer);
+ }
+ {
+ if (!name->uses || name->uses->scrap != scraps) {
+ Scrap_Node *use = (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ use->scrap = scraps;
+ use->next = name->uses;
+ name->uses = use;
+ }
+ }
+ c = source_get();
+ }
+ break;
+ default : fprintf(stderr, "%s: unexpected @%c in scrap (%s, %d)\n",
+ command_name, c, source_name, source_line);
+ exit(-1);
+ }
+ }
+ break;
+ default: push(c, &writer);
+ c = source_get();
+ break;
+ }
+ }
+ }
+}
+static char pop(manager)
+ Manager *manager;
+{
+ Slab *scrap = manager->scrap;
+ int index = manager->index;
+ char c = scrap->chars[index++];
+ if (index == SLAB_SIZE) {
+ manager->scrap = scrap->next;
+ index = 0;
+ }
+ manager->index = index;
+ return c;
+}
+static Name *pop_scrap_name(manager)
+ Manager *manager;
+{
+ char name[100];
+ char *p = name;
+ int c = pop(manager);
+ while (TRUE) {
+ if (c == '@')
+ {
+ c = pop(manager);
+ if (c == '@') {
+ *p++ = c;
+ c = pop(manager);
+ }
+ else if (c == '>') {
+ if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') {
+ p[-3] = ' ';
+ p -= 2;
+ }
+ *p = '\0';
+ return prefix_add(&macro_names, name);
+ }
+ else {
+ fprintf(stderr, "%s: found an internal problem (1)\n", command_name);
+ exit(-1);
+ }
+ }
+ else {
+ *p++ = c;
+ c = pop(manager);
+ }
+ }
+}
+int write_scraps(file, defs, global_indent, indent_chars,
+ debug_flag, tab_flag, indent_flag)
+ FILE *file;
+ Scrap_Node *defs;
+ int global_indent;
+ char *indent_chars;
+ char debug_flag;
+ char tab_flag;
+ char indent_flag;
+{
+ int indent = 0;
+ while (defs) {
+ {
+ char c;
+ Manager reader;
+ int line_number = scrap_array(defs->scrap).file_line;
+ if (debug_flag) {
+ fprintf(file, "\n#line %d \"%s\"\n",
+ line_number, scrap_array(defs->scrap).file_name);
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ }
+ reader.scrap = scrap_array(defs->scrap).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ switch (c) {
+ case '@': {
+ c = pop(&reader);
+ switch (c) {
+ case '@': putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ case '<': {
+ Name *name = pop_scrap_name(&reader);
+ if (name->mark) {
+ fprintf(stderr, "%s: recursive macro discovered involving <%s>\n",
+ command_name, name->spelling);
+ exit(-1);
+ }
+ if (name->defs) {
+ name->mark = TRUE;
+ indent = write_scraps(file, name->defs, global_indent + indent,
+ indent_chars, debug_flag, tab_flag, indent_flag);
+ indent -= global_indent;
+ name->mark = FALSE;
+ }
+ else if (!tex_flag)
+ fprintf(stderr, "%s: macro never defined <%s>\n",
+ command_name, name->spelling);
+ }
+ if (debug_flag) {
+ fprintf(file, "\n#line %d \"%s\"\n",
+ line_number, scrap_array(defs->scrap).file_name);
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ }
+ break;
+ default: /* ignore, since we should already have a warning */
+ break;
+ }
+ }
+ break;
+ case '\n': putc(c, file);
+ line_number++;
+ {
+ if (indent_flag) {
+ if (tab_flag)
+ for (indent=0; indent<global_indent; indent++)
+ putc(' ', file);
+ else
+ for (indent=0; indent<global_indent; indent++)
+ putc(indent_chars[indent], file);
+ }
+ indent = 0;
+ }
+ break;
+ case '\t': {
+ if (tab_flag)
+ {
+ int delta = 8 - (indent % 8);
+ indent += delta;
+ while (delta > 0) {
+ putc(' ', file);
+ delta--;
+ }
+ }
+ else {
+ putc('\t', file);
+ indent_chars[global_indent + indent] = '\t';
+ indent++;
+ }
+ }
+ break;
+ default: putc(c, file);
+ indent_chars[global_indent + indent] = ' ';
+ indent++;
+ break;
+ }
+ c = pop(&reader);
+ }
+ }
+ defs = defs->next;
+ }
+ return indent + global_indent;
+}
+
+typedef struct name_node {
+ struct name_node *next;
+ Name *name;
+} Name_Node;
+
+typedef struct goto_node {
+ struct goto_node *next; /* next goto node with same depth */
+ struct goto_node *fail;
+ struct move_node *moves;
+ Name_Node *output;
+} Goto_Node;
+
+typedef struct move_node {
+ struct move_node *next;
+ Goto_Node *state;
+ char c;
+} Move_Node;
+
+static Goto_Node *root[128];
+static int max_depth;
+static Goto_Node **depths;
+static Goto_Node *goto_lookup(c, g)
+ char c;
+ Goto_Node *g;
+{
+ Move_Node *m = g->moves;
+ while (m && m->c != c)
+ m = m->next;
+ if (m)
+ return m->state;
+ else
+ return NULL;
+}
+
+static void build_gotos();
+
+void search()
+{
+ int i;
+ for (i=0; i<128; i++)
+ root[i] = NULL;
+ max_depth = 10;
+ depths = (Goto_Node **) arena_getmem(max_depth * sizeof(Goto_Node *));
+ for (i=0; i<max_depth; i++)
+ depths[i] = NULL;
+ build_gotos(user_names);
+ {
+ int depth;
+ for (depth=1; depth<max_depth; depth++) {
+ Goto_Node *r = depths[depth];
+ while (r) {
+ Move_Node *m = r->moves;
+ while (m) {
+ char a = m->c;
+ Goto_Node *s = m->state;
+ Goto_Node *state = r->fail;
+ while (state && !goto_lookup(a, state))
+ state = state->fail;
+ if (state)
+ s->fail = goto_lookup(a, state);
+ else
+ s->fail = root[a];
+ if (s->fail) {
+ Name_Node *p = s->fail->output;
+ while (p) {
+ Name_Node *q = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->name = p->name;
+ q->next = s->output;
+ s->output = q;
+ p = p->next;
+ }
+ }
+ m = m->next;
+ }
+ r = r->next;
+ }
+ }
+ }
+ {
+ for (i=1; i<scraps; i++) {
+ char c;
+ Manager reader;
+ Goto_Node *state = NULL;
+ reader.scrap = scrap_array(i).slab;
+ reader.index = 0;
+ c = pop(&reader);
+ while (c) {
+ while (state && !goto_lookup(c, state))
+ state = state->fail;
+ if (state)
+ state = goto_lookup(c, state);
+ else
+ state = root[c];
+ if (state && state->output) {
+ Name_Node *p = state->output;
+ do {
+ Name *name = p->name;
+ if (!name->uses || name->uses->scrap != i) {
+ Scrap_Node *new_use =
+ (Scrap_Node *) arena_getmem(sizeof(Scrap_Node));
+ new_use->scrap = i;
+ new_use->next = name->uses;
+ name->uses = new_use;
+ }
+ p = p->next;
+ } while (p);
+ }
+ c = pop(&reader);
+ }
+ }
+ }
+}
+static void build_gotos(tree)
+ Name *tree;
+{
+ while (tree) {
+ {
+ int depth = 2;
+ char *p = tree->spelling;
+ char c = *p++;
+ Goto_Node *q = root[c];
+ if (!q) {
+ q = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ root[c] = q;
+ q->moves = NULL;
+ q->fail = NULL;
+ q->moves = NULL;
+ q->output = NULL;
+ q->next = depths[1];
+ depths[1] = q;
+ }
+ while (c = *p++) {
+ Goto_Node *new = goto_lookup(c, q);
+ if (!new) {
+ Move_Node *new_move = (Move_Node *) arena_getmem(sizeof(Move_Node));
+ new = (Goto_Node *) arena_getmem(sizeof(Goto_Node));
+ new->moves = NULL;
+ new->fail = NULL;
+ new->moves = NULL;
+ new->output = NULL;
+ new_move->state = new;
+ new_move->c = c;
+ new_move->next = q->moves;
+ q->moves = new_move;
+ if (depth == max_depth) {
+ int i;
+ Goto_Node **new_depths =
+ (Goto_Node **) arena_getmem(2*depth*sizeof(Goto_Node *));
+ max_depth = 2 * depth;
+ for (i=0; i<depth; i++)
+ new_depths[i] = depths[i];
+ depths = new_depths;
+ for (i=depth; i<max_depth; i++)
+ depths[i] = NULL;
+ }
+ new->next = depths[depth];
+ depths[depth] = new;
+ }
+ q = new;
+ depth++;
+ }
+ q->output = (Name_Node *) arena_getmem(sizeof(Name_Node));
+ q->output->next = NULL;
+ q->output->name = tree;
+ }
+ build_gotos(tree->rlink);
+ tree = tree->llink;
+ }
+}