#line 932 "nuweb.w" #include "global.h" #line 5126 "nuweb.w" enum { LESS, GREATER, EQUAL, PREFIX, EXTENSION }; static int compare(char *x, char *y) { int len, result; int xl = strlen(x); int yl = strlen(y); int xp = x[xl - 1] == ' '; int yp = y[yl - 1] == ' '; if (xp) xl--; if (yp) yl--; len = xl < yl ? xl : yl; result = strncmp(x, y, len); if (result < 0) return GREATER; else if (result > 0) return LESS; else if (xl < yl) { if (xp) return EXTENSION; else return LESS; } else if (xl > yl) { if (yp) return PREFIX; else return GREATER; } else return EQUAL; } #line 5155 "nuweb.w" char *save_string(char *s) { char *new = (char *) arena_getmem((strlen(s) + 1) * sizeof(char)); strcpy(new, s); return new; } #line 5164 "nuweb.w" static int ambiguous_prefix(Name *node, char *spelling, unsigned char sector); static char * found_name = NULL; Name *prefix_add(Name **rt, char *spelling, unsigned char sector) { Name *node = *rt; int cmp; while (node) { switch ((cmp = compare(node->spelling, spelling))) { case GREATER: rt = &node->rlink; break; case LESS: rt = &node->llink; break; case EQUAL: found_name = node->spelling; case EXTENSION: if (node->sector > sector) { rt = &node->rlink; break; } else if (node->sector < sector) { rt = &node->llink; break; } if (cmp == EXTENSION) node->spelling = save_string(spelling); return node; case PREFIX: #line 5207 "nuweb.w" { if (ambiguous_prefix(node->llink, spelling, sector) || ambiguous_prefix(node->rlink, spelling, sector)) fprintf(stderr, "%s: ambiguous prefix %c<%s...%c> (%s, line %d)\n", command_name, nw_char, spelling, nw_char, source_name, source_line); } #line 5193 "nuweb.w" return node; } node = *rt; } /* Create new name entry */ #line 5330 "nuweb.w" { node = (Name *) arena_getmem(sizeof(Name)); if (found_name && robs_strcmp(found_name, spelling) == 0) node->spelling = found_name; else node->spelling = save_string(spelling); node->mark = FALSE; node->llink = NULL; node->rlink = NULL; node->uses = NULL; node->defs = NULL; node->arg[0] = node->arg[1] = node->arg[2] = node->arg[3] = node->arg[4] = node->arg[5] = node->arg[6] = node->arg[7] = node->arg[8] = NULL; node->tab_flag = TRUE; node->indent_flag = TRUE; node->debug_flag = FALSE; node->comment_flag = 0; node->sector = sector; *rt = node; return node; } #line 5198 "nuweb.w" } #line 5216 "nuweb.w" static int ambiguous_prefix(Name *node, char *spelling, unsigned char sector) { while (node) { switch (compare(node->spelling, spelling)) { case GREATER: node = node->rlink; break; case LESS: node = node->llink; break; case EXTENSION: case PREFIX: case EQUAL: if (node->sector > sector) { node = node->rlink; break; } else if (node->sector < sector) { node = node->llink; break; } return TRUE; } } return FALSE; } #line 5264 "nuweb.w" int robs_strcmp(char* x, char* y) { int cmp = 0; for (; *x && *y; x++, y++) { /* Skip invisibles on 'x' */ #line 5298 "nuweb.w" if (*x == '|') x++; #line 5270 "nuweb.w" /* Skip invisibles on 'y' */ #line 5298 "nuweb.w" if (*y == '|') y++; #line 5271 "nuweb.w" if (*x == *y) continue; if (islower(*x) && toupper(*x) == *y) { if (!cmp) cmp = 1; continue; } if (islower(*y) && *x == toupper(*y)) { if (!cmp) cmp = -1; continue; } return 2*(toupper(*x) - toupper(*y)); } if (*x) return 2; if (*y) return -2; return cmp; } #line 5303 "nuweb.w" Name *name_add(Name **rt, char *spelling, unsigned char sector) { Name *node = *rt; while (node) { int result = robs_strcmp(node->spelling, spelling); if (result > 0) rt = &node->llink; else if (result < 0) rt = &node->rlink; else { found_name = node->spelling; if (node->sector > sector) rt = &node->llink; else if (node->sector < sector) rt = &node->rlink; else return node; } node = *rt; } /* Create new name entry */ #line 5330 "nuweb.w" { node = (Name *) arena_getmem(sizeof(Name)); if (found_name && robs_strcmp(found_name, spelling) == 0) node->spelling = found_name; else node->spelling = save_string(spelling); node->mark = FALSE; node->llink = NULL; node->rlink = NULL; node->uses = NULL; node->defs = NULL; node->arg[0] = node->arg[1] = node->arg[2] = node->arg[3] = node->arg[4] = node->arg[5] = node->arg[6] = node->arg[7] = node->arg[8] = NULL; node->tab_flag = TRUE; node->indent_flag = TRUE; node->debug_flag = FALSE; node->comment_flag = 0; node->sector = sector; *rt = node; return node; } #line 5324 "nuweb.w" } #line 5363 "nuweb.w" Name *collect_file_name(void) { Name *new_name; char name[MAX_NAME_LEN]; char *p = name; int start_line = source_line; int c = source_get(), c2; while (isspace(c)) c = source_get(); while (isgraph(c)) { *p++ = c; c = source_get(); } if (p == name) { fprintf(stderr, "%s: expected file name (%s, %d)\n", command_name, source_name, start_line); exit(-1); } *p = '\0'; /* File names are always global. */ new_name = name_add(&file_names, name, 0); /* Handle optional per-file flags */ #line 5396 "nuweb.w" { while (1) { while (isspace(c)) c = source_get(); if (c == '-') { c = source_get(); do { switch (c) { case 't': new_name->tab_flag = FALSE; break; case 'd': new_name->debug_flag = TRUE; break; case 'i': new_name->indent_flag = FALSE; break; case 'c': #line 5425 "nuweb.w" c = source_get(); if (c == 'c') new_name->comment_flag = 1; else if (c == '+') new_name->comment_flag = 2; else if (c == 'p') new_name->comment_flag = 3; else fprintf(stderr, "%s: Unrecognised comment flag (%s, %d)\n", command_name, source_name, source_line); #line 5410 "nuweb.w" break; default : fprintf(stderr, "%s: unexpected per-file flag (%s, %d)\n", command_name, source_name, source_line); break; } c = source_get(); } while (!isspace(c)); } else break; } } #line 5384 "nuweb.w" c2 = source_get(); if (c != nw_char || (c2 != '{' && c2 != '(' && c2 != '[')) { fprintf(stderr, "%s: expected %c{, %c[, or %c( after file name (%s, %d)\n", command_name, nw_char, nw_char, nw_char, source_name, start_line); exit(-1); } return new_name; } #line 5446 "nuweb.w" Name *collect_macro_name(void) { char name[MAX_NAME_LEN]; char args[1000]; char * arg[9]; char * argp = args; int argc = 0; char *p = name; int start_line = source_line; int c = source_get(), c2; unsigned char sector = current_sector; if (c == '+') { sector = 0; c = source_get(); } while (isspace(c)) c = source_get(); while (c != EOF) { Name * node; switch (c) { case '\t': case ' ': *p++ = ' '; do c = source_get(); while (c == ' ' || c == '\t'); break; case '\n': #line 5564 "nuweb.w" { do c = source_get(); while (isspace(c)); c2 = source_get(); if (c != nw_char || (c2 != '{' && c2 != '(' && c2 != '[')) { fprintf(stderr, "%s: expected %c{ after fragment name (%s, %d)\n", command_name, nw_char, source_name, start_line); exit(-1); } /* Cleanup and install name */ #line 5547 "nuweb.w" { if (p > name && p[-1] == ' ') p--; if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') { p[-3] = ' '; p -= 2; } if (p == name || name[0] == ' ') { fprintf(stderr, "%s: empty name (%s, %d)\n", command_name, source_name, source_line); exit(-1); } *p = '\0'; node = prefix_add(¯o_names, name, sector); } #line 5574 "nuweb.w" return install_args(node, argc, arg); } #line 5473 "nuweb.w" default: if (c==nw_char) { /* Check for terminating at-sequence and return name */ #line 5494 "nuweb.w" { c = source_get(); switch (c) { case '(': case '[': case '{': #line 5547 "nuweb.w" { if (p > name && p[-1] == ' ') p--; if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') { p[-3] = ' '; p -= 2; } if (p == name || name[0] == ' ') { fprintf(stderr, "%s: empty name (%s, %d)\n", command_name, source_name, source_line); exit(-1); } *p = '\0'; node = prefix_add(¯o_names, name, sector); } #line 5499 "nuweb.w" return install_args(node, argc, arg); case '\'': #line 5517 "nuweb.w" arg[argc] = argp; while ((c = source_get()) != EOF) { if (c==nw_char) { c2 = source_get(); if (c2=='\'') { /* Make this argument */ #line 5540 "nuweb.w" if (argc < 9) { *argp++ = '\000'; argc += 1; } #line 5522 "nuweb.w" c = source_get(); break; } else *argp++ = c2; } else *argp++ = c; } *p++ = ARG_CHR; #line 5501 "nuweb.w" break; default: if (c==nw_char) { *p++ = c; break; } fprintf(stderr, "%s: unexpected %c%c in fragment definition name (%s, %d)\n", command_name, nw_char, c, source_name, start_line); exit(-1); } } #line 5477 "nuweb.w" break; } *p++ = c; c = source_get(); break; } } fprintf(stderr, "%s: expected fragment name (%s, %d)\n", command_name, source_name, start_line); exit(-1); return NULL; /* unreachable return to avoid warnings on some compilers */ } #line 5583 "nuweb.w" Name *install_args(Name * name, int argc, char *arg[9]) { int i; for (i = 0; i < argc; i++) { if (name->arg[i] == NULL) name->arg[i] = save_string(arg[i]); } return name; } #line 5604 "nuweb.w" Arglist * buildArglist(Name * name, Arglist * a) { Arglist * args = (Arglist *)arena_getmem(sizeof(Arglist)); args->args = a; args->next = NULL; args->name = name; return args; } #line 5617 "nuweb.w" Arglist * collect_scrap_name(int current_scrap) { char name[MAX_NAME_LEN]; char *p = name; int c = source_get(); unsigned char sector = current_sector; Arglist * head = NULL; Arglist ** tail = &head; if (c == '+') { sector = 0; c = source_get(); } while (c == ' ' || c == '\t') c = source_get(); while (c != EOF) { switch (c) { case '\t': case ' ': *p++ = ' '; do c = source_get(); while (c == ' ' || c == '\t'); break; default: if (c==nw_char) { /* Look for end of scrap name and return */ #line 5666 "nuweb.w" { Name * node; c = source_get(); switch (c) { case '\'': { /* Add plain string argument */ #line 5723 "nuweb.w" char buff[MAX_NAME_LEN]; char * s = buff; int c, c2; while ((c = source_get()) != EOF) { if (c==nw_char) { c2 = source_get(); if (c2=='\'') break; *s++ = c2; } else *s++ = c; } *s = '\000'; /* Add buff to current arg list */ #line 5774 "nuweb.w" *tail = buildArglist(NULL, (Arglist *)save_string(buff)); tail = &(*tail)->next; #line 5738 "nuweb.w" #line 5673 "nuweb.w" } *p++ = ARG_CHR; c = source_get(); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { /* Add a propagated argument */ #line 5744 "nuweb.w" char buff[3]; buff[0] = ARG_CHR; buff[1] = c; buff[2] = '\000'; /* Add buff to current arg list */ #line 5774 "nuweb.w" *tail = buildArglist(NULL, (Arglist *)save_string(buff)); tail = &(*tail)->next; #line 5748 "nuweb.w" #line 5681 "nuweb.w" } *p++ = ARG_CHR; c = source_get(); break; case '{': { /* Add an inline scrap argument */ #line 5751 "nuweb.w" int s = collect_scrap(); Scrap_Node * d = (Scrap_Node *)arena_getmem(sizeof(Scrap_Node)); d->scrap = s; d->quoted = 0; d->next = NULL; *tail = buildArglist((Name *)1, (Arglist *)d); tail = &(*tail)->next; #line 5687 "nuweb.w" } *p++ = ARG_CHR; c = source_get(); break; case '<': /* Add macro call argument */ #line 5767 "nuweb.w" *tail = collect_scrap_name(current_scrap); if (current_scrap >= 0) add_to_use((*tail)->name, current_scrap); tail = &(*tail)->next; #line 5693 "nuweb.w" *p++ = ARG_CHR; c = source_get(); break; case '(': scrap_name_has_parameters = 1; /* Cleanup and install name */ #line 5547 "nuweb.w" { if (p > name && p[-1] == ' ') p--; if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') { p[-3] = ' '; p -= 2; } if (p == name || name[0] == ' ') { fprintf(stderr, "%s: empty name (%s, %d)\n", command_name, source_name, source_line); exit(-1); } *p = '\0'; node = prefix_add(¯o_names, name, sector); } #line 5699 "nuweb.w" return buildArglist(node, head); case '>': scrap_name_has_parameters = 0; /* Cleanup and install name */ #line 5547 "nuweb.w" { if (p > name && p[-1] == ' ') p--; if (p - name > 3 && p[-1] == '.' && p[-2] == '.' && p[-3] == '.') { p[-3] = ' '; p -= 2; } if (p == name || name[0] == ' ') { fprintf(stderr, "%s: empty name (%s, %d)\n", command_name, source_name, source_line); exit(-1); } *p = '\0'; node = prefix_add(¯o_names, name, sector); } #line 5703 "nuweb.w" return buildArglist(node, head); default: if (c==nw_char) { *p++ = c; c = source_get(); break; } fprintf(stderr, "%s: unexpected %c%c in fragment invocation name (%s, %d)\n", command_name, nw_char, c, source_name, source_line); exit(-1); } } #line 5644 "nuweb.w" break; } if (!isgraph(c)) { fprintf(stderr, "%s: unexpected character in fragment name (%s, %d)\n", command_name, source_name, source_line); exit(-1); } *p++ = c; c = source_get(); break; } } fprintf(stderr, "%s: unexpected end of file (%s, %d)\n", command_name, source_name, source_line); exit(-1); return NULL; /* unreachable return to avoid warnings on some compilers */ } #line 5779 "nuweb.w" static Scrap_Node *reverse(Scrap_Node *a); /* a forward declaration */ void reverse_lists(Name *names) { while (names) { reverse_lists(names->llink); names->defs = reverse(names->defs); names->uses = reverse(names->uses); names = names->rlink; } } #line 5796 "nuweb.w" static Scrap_Node *reverse(Scrap_Node *a) { if (a) { Scrap_Node *b = a->next; a->next = NULL; while (b) { Scrap_Node *c = b->next; b->next = a; a = b; b = c; } } return a; }